tags:

views:

301

answers:

4

How would I go about removing a number of bytes from a byte array?

+6  A: 

You could do this:

using System.Linq

// ...

var newArray = oldArray.Skip(numBytes).ToArray();
Jacob
A: 

If you can't use Linq, you could do it this way:

byte[] myArray = // however you acquire the array

byte[] newArray = new byte[myArray.Length - 16];

for (int i = 0; i < newArray.Length; i++)
{
    newArray[i] = myArray[i + 16];
}

// newArray is now myArray minus the first 16 bytes

You'll also need to handle the case where the array is less than 16 bytes long.

Zach Johnson
+8  A: 

EDIT: As nobugz's comment (and Reed Copsey's answer) mentions, if you don't actually need the result as a byte array, you should look into using ArraySegment<T>:

ArraySegment<byte> segment = new ArraySegment<byte>(full, 16, full.Length - 16);

Otherwise, copying will be necessary - arrays always have a fixed size, so you can't "remove" the first 16 bytes from the existing array. Instead, you'll have to create a new, smaller array and copy the relevant data into it.

Zach's suggestion is along the right lines for the non-LINQ approach, but it can be made simpler (this assumes you already know the original array is at least 16 bytes long):

byte[] newArray = new byte[oldArray.Length - 16];
Buffer.BlockCopy(oldArray, 16, newArray, 0, newArray.Length);

or

byte[] newArray = new byte[oldArray.Length - 16];
Array.Copy(oldArray, 16, newArray, 0, newArray.Length);

I suspect Buffer.BlockCopy will be slightly faster, but I don't know for sure.

Note that both of these could be significantly more efficient than the LINQ approach if the arrays involved are big: the LINQ approach requires each byte to be individually returned from an iterator, and potentially intermediate copies to be made (in the same way as adding items to a List<T> needs to grow the backing array periodically). Obviously don't micro-optimise, but it's worth checking if this bit of code is a performance bottleneck.

EDIT: I ran a very "quick and dirty" benchmark of the three approaches. I don't trust the benchmark to distinguish between Buffer.BlockCopy and Array.Copy - they were pretty close - but the LINQ approach was over 100 times slower.

On my laptop, using byte arrays of 10,000 elements, it took nearly 10 seconds to perform 40,000 copies using LINQ; the above approaches took about 80ms to do the same amount of work. I upped the iteration count to 4,000,000 and it still only took about 7 seconds. Obviously the normal caveats around micro-benchmarks apply, but this is a pretty significat difference.

Definitely use the above approach if this is in a code path which is important to performance :)

Jon Skeet
+1, buffering is definitely more efficient for large arrays.
Zach Johnson
What's the difference between Buffer.BlockCopy and Array.Copy when used with byte arrays?
dtb
@dtb: I don't expect there to be any functional difference in this case. `Buffer.BlockCopy` is a bit more restrictive - I suspect it's implemented in a lower-level manner, but I don't know the details.
Jon Skeet
@dtb: It appears from the msdn documentation that `Array.Copy` copies the array one element at a time (the docs say: `This method is an O(n) operation, where n is length`), but `Buffer.BlockCopy` copies a block of bytes as a whole (I assume creating another array temporarily to store the copied bytes).
Zach Johnson
@Zach: Why would either of them need a temporary array, unless they're copying from one section of an array to an overlapping section of the same array?
Jon Skeet
@Jon Skeet: It sounds like from the documentation on `Buffer.BlockCopy`, http://msdn.microsoft.com/en-us/library/system.buffer.blockcopy.aspx, that it is intended for use where you may copy overlapping sections. From the docs: "As its name suggests, the BlockCopy method copies a block of bytes as a whole, rather than copying one byte at a time. Therefore, if src and dst reference the same array, and the range from srcOffset + count -1 overlaps the range from dstOffset + count - 1, the values of the overlapping bytes are not overwritten before they are copied to the destination."
Zach Johnson
@Zach: It's intended to *cope* with overlapping sections, but I doubt that it copies twice if it doesn't need to.
Jon Skeet
+5  A: 

I will also mention - depending on how you plan to use the results, often, an alternative approach is to use ArraySegment<T> to just access the remaining portion of the array. This prevents the need to copy the array, which can be more efficient in some usage scenarios:

ArraySegment<byte> segment = new ArraySegment<byte>(originalArray, 16, originalArray.Length-16);

// Use segment how you'd use your array...  
Reed Copsey