views:

102

answers:

6

This is a simple one, and one that I thought would have been answered. I did try to find an answer on here, but didn't come up with anything - so apologies if there is something I have missed.

Anyway, is there an equivalent of StringBuilder but for byte arrays?

I'm not bothered about all the different overloads of Append() - but I'd like to see Append(byte) and Append(byte[]).

Is there anything around or is it roll-your-own time?

+7  A: 

Probably List<byte>:

var byteList = new List<byte>();
byteList.Add(42);
byteList.AddRange(new byte[] { 1, 2, 3 });
LukeH
...and then Append(byte) becomes Add(byte) and Append(byte[]) becomes AddRange(byte[]).
Justin Niessner
Note that as with `StringBuilder`, adding elements to a `List` is amortized O(1).
Brian
Ok, cool - just one question... Would that be as efficient? I know List<> does some efficient copies for AddRange under the hood, but I didn't know if that works out as the most efficient way to do it?
Matt Whitfield
@Matt : As with `StringBuilder`, C# `List` uses a backing capacity greater than the size of the data structure in order to enable constant time insertions. This capacity is doubled as needed. This strategy is the same strategy `StringBuilder` uses to avoid excessive memory allocations.
Brian
@Brian - Actually, what I was referring to was the way that List<> checks to see if the IEnumerable it is adding in AddRange is an ICollection too, and if it is it adds the elements in a different way... I can't remember exactly how, because I'm not at a machine where I have the reference code downloaded...
Matt Whitfield
@Matt: Yes, if you pass an `ICollection<T>` then the `AddRange` method uses the collection's `Count` property in order pre-allocate the list to the right size (if necessary). If it's not an `ICollection<T>` then the list will need to be resized on-the-fly as the elements are added.
LukeH
+8  A: 

Would MemoryStream work for you? The interface might not be quite as convenient, but it offers a simple way to append bytes, and when you are done you can get the contents as a byte[] by calling ToArray().

A more StringBuilder-like interface could probably be achieved by making an extension method.

Update
Extension methods could look like this:

public static class MemoryStreamExtensions
{
    public static void Append(this MemoryStream stream, byte value)
    {
        stream.Append(new[] { value });
    }

    public static void Append(this MemoryStream stream, byte[] values)
    {
        stream.Write(values, 0, values.Length);
    }
}

Usage:

MemoryStream stream = new MemoryStream();
stream.Append(67);
stream.Append(new byte[] { 68, 69 });
byte[] data = stream.ToArray();  // gets an array with bytes 67, 68 and 69
Fredrik Mörk
Yes it would - I like that approach... Thanks
Matt Whitfield
Can I just ask - I haven't actually seen the syntax `new[] { value }` before - is that inferring the type of the array?
Matt Whitfield
@Matt: yes, that is correct. In the extension method, `value` is of type `byte`, so `byte[]` is inferred. In the last sample I need to specify `new byte[]` since the compiler would infer the type `int` otherwise.
Fredrik Mörk
@Frederik Mörk - Awesome - thanks. Accepting for the extra 'I've learned something new today' goodness.
Matt Whitfield
@Fredrik Mörk: Is there any way to munch data from the start of a MemoryStream, so it works like a queue, or is there any other CLR class which can be used as an intra-process pipe?
supercat
@supercat: as far as I know, there is no functionality in `MemoryStream` for that. I don't know any other class than [`Queue<byte>`](http://msdn.microsoft.com/en-us/library/7977ey2c.aspx) from the top of my head.
Fredrik Mörk
+2  A: 

List<byte> Then when you want it as an array you can call ToArray()

Aaron
A: 

you can create an extension method to support this

saurabh
A: 

I would say the closet match would be Buffer class http://msdn.microsoft.com/en-us/library/system.buffer.aspx

Buffer.BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count);
CodeCanvas
`Buffer` just has a handful of static methods for manipulating arrays.
LukeH
+3  A: 

The MemoryStream approach is good, but if you want to have StringBuilder-like behavior add a BinaryWriter. BinaryWriter provides all the Write overrides you could want.

MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
writer.Write((byte)67);
writer.Write(new byte[] { 68, 69 });
Tergiver