2012-05-10 11 views
5

Tengo un búfer de matriz de bytes de tamaño máximo 1K. Quiero escribir un subconjunto de la matriz (el comienzo del subconjunto siempre será el elemento 0, pero la longitud que nos interesa es en una variable).¿Cómo obtengo eficientemente un subconjunto de una matriz de bytes (primeros N elementos) en C#?

La aplicación aquí es de compresión. Paso en un buffer a una función de compresión. Para simplificar, suponga que la compresión dará lugar a datos que son iguales o inferiores a 1K bytes.

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? 
} 

realmente me gustaría evitar una copia aquí - parece completamente innecesario ya que todos los datos necesarios es en buffer ya.

Respuesta

6

Si no puede cambiar la firma del método, entonces está atascado. No puede crear una "vista" sobre una matriz de bytes con tipo byte []. La solución ideal para eso sería que la operación tome un ArraySegment<byte> o un byte[] seguido de un desplazamiento y un conteo. Si realmente no puede cambiar el método de Escritura, desafortunadamente tiene que crear una nueva matriz y copiar los datos.

+0

Wow, me has ayudado con WCF antes (como un usuario diferente). Gracias de nuevo por el consejo Carlos +1. – jglouie

2

Si la firma del método es (byte[]), no puede hacer nada más que copiar.

si se puede cambiar la firma:

  • corrientes admite la escritura subconjuntos de matrices, por lo que no es inusual petición de tener la firma como Stream.Write:

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

  • la otra opción es para pasar IEnumerable<byte> para que pueda cortar su matriz de la forma que desee sin copiar.

11

Buffer.BlockCopy sería mi elección.

ejemplo Microsoft: 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 

Su código se vería así:

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

No hay manera de que puede hacerlo. Array.Resize en lugar de cambiar la longitud de la matriz, simplemente la copia a una nueva instancia de matriz.

Sin embargo, se puede utilizar el Buffer class, que tiene un mejor rendimiento:

Buffer proporciona métodos para copiar bytes de una variedad de tipos primitivos a otra matriz de tipos primitivos, obtener un byte de una matriz, establecer un byte en una matriz y obtener la longitud de una matriz. Esta clase proporciona un mejor rendimiento para manipular tipos primitivos que métodos similares en la clase System.Array.

Esto concuerda con sus necesidades, porque tiene una matriz de bytes y el byte es de tipo primitivo.

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

Esto le permite obtener cualquier sección del medio que desee.Es muy probable que haga una copia, pero no creo que deba intentar evitar eso.

Cuestiones relacionadas