字节数组的StringBuilder等价物

42

这是一个简单的问题,我认为应该已经有答案了。我尝试在这里找到答案,但没有找到任何东西-如果我漏掉了什么,请原谅。

那么,是否有类似StringBuilder但适用于字节数组的东西呢?

我不关心所有不同的Append()重载-但我想看到Append(byte)Append(byte [])

有类似的东西吗,还是需要自己实现?

6个回答

40

MemoryStream可行吗?该接口可能不太方便,但它提供了一种简单的方法来追加字节,完成后您可以通过调用ToArray()byte[]形式获取内容。

通过创建扩展方法,可以实现更类似于StringBuilder的接口。

更新
扩展方法可以这样写:

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);
    }
}

用法:

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

2
@Matt:是的,没错。在扩展方法中,value 的类型是 byte,因此会推断出 byte[]。在最后一个示例中,我需要指定 new byte[],否则编译器会推断出类型 int - Fredrik Mörk
1
@Fredrik Mörk:有没有办法从MemoryStream的开头获取数据,使其像队列一样工作,或者有没有其他可用作进程间管道的CLR类? - supercat
1
据我所知,MemoryStream 中没有这样的功能。我脑海中只能想到 Queue<byte> 这个类了。 - Fredrik Mörk
1
为了使其更像 StringBuilder,您可以让扩展方法返回流本身。虽然这可能会牺牲一些效率,但在构建器模式中,每个方法都返回构建器以便它们可以在一个长语句中调用并不是非常罕见的。 - Gurgadurgen
对于只接受单个字节的Append重载,使用stream.WriteByte(value)会更有效率,因为它可以避免中间的byte[]数组分配。 - Justin Van Patten
显示剩余4条评论

22

MemoryStream方法非常好,但如果您想要类似于StringBuilder的行为,请添加BinaryWriter。BinaryWriter提供了所有你需要的写入重载函数。

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

如果您需要特殊的编写器,也可以从BinaryWriter派生出一个新类。我创建了一个处理hton转换的编写器。 - Denise Skidmore
完成后,使用 stream.ToArray(); 获取数组。 - Peet Brits
2
请注意,BinaryWriterWrite(String) 方法会向流中写入长度前缀! - Lukas Körfer

12

可能是 List<byte>

var byteList = new List<byte>();
byteList.Add(42);
byteList.AddRange(new byte[] { 1, 2, 3 });

...然后Append(byte)变成了Add(byte),而Append(byte[])则变成了AddRange(byte[])。 - Justin Niessner
好的,很棒 - 只有一个问题...那样效率高吗?我知道 List<> 在幕后做了一些 AddRange 的高效复制,但我不确定它是否是最有效的方法? - Matt Whitfield
1
@Matt:是的,如果你传递了一个 ICollection<T>,那么 AddRange 方法将使用集合的 Count 属性来预先分配正确大小的列表(如果需要)。如果不是 ICollection<T>,则列表将需要在添加元素时动态调整大小。 - LukeH
你的答案在多样性、效率和接近StringBuilder方面与Fredrik Mörk的'MemoryStream'答案相比如何? - Dan W
StringBuilder 相较于 MemoryStream 突出的一个特性是 StringBuilder.Remove()。似乎 List<byte> 也提供了一种完全等效的方法,即 List<T>.RemoveRange()MemoryStream API 的不灵活性使我怀疑,在它和 List<T> 都支持的操作上,它可能会更高效,但我还没有进行测试。 - binki
显示剩余3条评论

3

List<byte>表示一个包含字节类型的列表,当你需要将其转换为数组时,可以调用ToArray()方法。


0

看看在codeproject上的this项目。 它只是实现了一个类,使用其他回答中建议的MemoryStream作为解决方案。


0
using System;
using System.IO;

public static class MemoryStreams
{
    public static MemoryStream Append(
        this MemoryStream stream
        , byte value
        , out bool done)
    {
        try
        {
            stream.WriteByte(value);
            done = true;
        }
        catch { done = false; }
        return stream;
    }

    public static MemoryStream Append(
        this MemoryStream stream
        , byte[] value
        , out bool done
        , uint offset = 0
        , Nullable<uint> count = null)
    {
        try
        {
            var rLenth = (uint)((value == null) ? 0 : value.Length);

            var rOffset = unchecked((int)(offset & 0x7FFFFFFF));

            var rCount = unchecked((int)((count ?? rLenth) & 0x7FFFFFFF));

            stream.Write(value, rOffset, rCount);
            done = true;
        }
        catch { done = false; }
        return stream;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接