2012-05-10 11 views
5

Ho un buffer di array di byte della dimensione massima 1K. Voglio scrivere un sottoinsieme dell'array (l'inizio del sottoinsieme sarà sempre l'elemento 0, ma la lunghezza a cui siamo interessati è in una variabile).Come posso ottenere in modo efficiente un sottoinsieme di un array di byte (primi N elementi) in C#?

L'applicazione qui è compressione. Passo in un buffer ad una funzione di compressione. Per semplicità, supponiamo che la compressione porterà a dati uguali o inferiori a 1K byte.

byte[] buffer = new byte[1024]; 
while (true) 
{ 
    uncompressedData = GetNextUncompressedBlock(); 
    int compressedLength = compress(buffer, uncompressedData); 

    // Here, compressedBuffer[0..compressedLength - 1] is what we're interested in 

    // There's a method now with signature Write(byte[] compressedData) that 
    // I won't be able to change. Short of allocating a custom sized buffer, 
    // and copying data into the custom sized buffer... is there any other 
    // technique I could use to only expose the data I want? 
} 

mi piacerebbe davvero evitare una copia qui - mi sembra del tutto inutile, in quanto tutti i dati necessari è in buffer già.

risposta

6

Se non riesci a modificare la firma del metodo, sei bloccato. Non è possibile creare una "vista" su un array di byte con tipo byte []. La soluzione ideale sarebbe l'operazione di prendere uno ArraySegment<byte> o uno byte[] seguito da un offset e un conteggio. Se davvero non puoi modificare il metodo Write, sfortunatamente sei bloccato con la creazione di un nuovo array e la copia dei dati su di esso.

+0

Wow, mi hai già aiutato con WCF (come utente diverso). Grazie ancora per la punta Carlos +1. – jglouie

2

Se la firma del metodo è (byte[]) non è possibile fare altro che copiare.

se si può cambiare la firma:

  • flussi supportano la scrittura sottoinsiemi di array, quindi non è richiesta insolita di avere la firma come Stream.Write:

    public abstract void Write( byte[] buffer, int offset, int count)

  • l'altra opzione è per passare IEnumerable<byte> in modo da poter suddividere il tuo array come vuoi senza copiare.

11

Buffer.BlockCopy sarebbe la mia scelta.

Microsoft esempio: http://msdn.microsoft.com/en-us/library/system.buffer.blockcopy.aspx

const int INT_SIZE = 4; 
int[] arr = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; 
Buffer.BlockCopy(arr, 3 * INT_SIZE, arr, 0 * INT_SIZE, 4 * INT_SIZE); 
foreach (int value in arr) 
    Console.Write("{0} ", value); 
// The example displays the following output: 
//  8 10 12 14 10 12 14 16 18 20 

Il codice sarà simile:

uncompressedData = GetNextUncompressedBlock();  
int compressedLength = compress(buffer, uncompressedData); 
Buffer.BlockCopy(buffer, 0, buffer, 0, compressedLength); 
3

Non c'è modo si può fare. Array.Resize invece di modificare la lunghezza dell'array, semplicemente lo copia in una nuova istanza di array.

Tuttavia, è possibile utilizzare il Buffer class, che ha prestazioni migliori:

Buffer fornisce i metodi per copiare i byte da un array di tipi primitivi ad un altro array di tipi primitivi, ottenere un byte da un array, set un byte in un array e ottenere la lunghezza di un array. Questa classe fornisce prestazioni migliori per la manipolazione dei tipi primitivi rispetto ai metodi simili nella classe System.Array.

Questo corrisponde alle tue esigenze, perché hai una matrice di byte e il byte è un tipo primitivo.

2
byte[] b = new Byte[] {1, 2, 3, 4, 5}; 
    IEnumerable<Byte> middle = b.Skip(2).Take(3); 

Questo dovrebbe consentire di ottenere qualsiasi sezione centrale che ti piace.Questo probabilmente ne fa una copia, ma non penso che dovresti tentare di evitarlo.

Problemi correlati