How to efficiently get a subset of a byte array (first N elements) in C #?

I have a maximum size 1K byte array buffer. I want to write a subset of the array (the beginning of the subset will always be element 0, but the length of interest to us is in a variable).

The application here is compression. I pass the buffer to the compression function. For simplicity, suppose that compression will cause the data to be equal to or less than 1 Kbyte.

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

I would really like to avoid copying here - this seems completely unnecessary, since all the necessary data is already in the buffer .

+5
source share
5 answers

If you cannot change the method signature, then you are stuck. You cannot create a "view" over a byte array with the byte type []. An ideal solution for this would be to either take ArraySegment<byte> or byte[] , followed by offset and count. If you really cannot change the Write method, then, unfortunately, you are stuck in creating a new array and copying data to it.

+6
source

Buffer.BlockCopy will be my choice.

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

Your code will look like this:

 uncompressedData = GetNextUncompressedBlock(); int compressedLength = compress(buffer, uncompressedData); Buffer.BlockCopy(buffer, 0, buffer, 0, compressedLength); 
+11
source

Impossible to do this. Array.Resize, instead of changing the length of the array, simply copies it to a new instance of the array.

However, you can use the Buffer class , which has better performance:

The buffer provides methods for copying bytes from one array of primitive types to another array of primitive types, getting a byte from an array, setting a byte in an array, and getting the length of the array. This class provides better performance for managing primitive types than similar methods in the System.Array class.

This suits your needs because you have an array of bytes and a byte is a primitive type.

+3
source

If the signature is a method (byte[]) , you can do nothing but copy.

If you can change the signature:

  • Stream support supports subsets of arrays, so there is no unusual request to have a signature of type Stream.Write :

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

  • another option is to pass an IEnumerable<byte> so that you can slice the array in any way you want without copying.

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

This will allow you to get any middle section that you like. It most likely makes a copy, but I do not think you should try to avoid this.

+2
source

Source: https://habr.com/ru/post/922158/


All Articles