连接byte []的C#列表

时间:2011-02-02 15:02:59

标签: c# list bytearray concatenation

我正在创建几个字节数组,需要连接在一起才能创建一个大字节数组 - 我宁愿不使用byte [],但在这里别无选择......

我在创建它们时将每个添加到List中,所以我只需要在拥有所有byte []后进行连接,但我的问题是,实际执行此操作的最佳方法是什么?

当我有一个包含未知数量的byte []的列表时,我想将它们连在一起。

感谢。

6 个答案:

答案 0 :(得分:20)

listOfByteArrs.SelectMany(byteArr=>byteArr).ToArray()

上面的代码将一系列字节序列连接成一个序列 - 并将结果存储在一个数组中。

虽然可读,但这并不是最有效的 - 它没有利用你已经知道结果字节数组长度的事实,因此可以避免动态扩展.ToArray()实现这必然涉及多个分配和数组副本。此外,SelectMany是根据迭代器实现的;这意味着很多+很多接口调用很慢。但是,对于小型数据集大小,这不太重要。

如果您需要更快的实施,您可以执行以下操作:

var output = new byte[listOfByteArrs.Sum(arr=>arr.Length)];
int writeIdx=0;
foreach(var byteArr in listOfByteArrs) {
    byteArr.CopyTo(output, writeIdx);
    writeIdx += byteArr.Length;
}

或Martinho建议:

var output = new byte[listOfByteArrs.Sum(arr => arr.Length)];
using(var stream = new MemoryStream(output))
    foreach (var bytes in listOfByteArrs)
        stream.Write(bytes, 0, bytes.Length);

一些时间:

var listOfByteArrs = Enumerable.Range(1,1000)
    .Select(i=>Enumerable.Range(0,i).Select(x=>(byte)x).ToArray()).ToList();

使用short方法连接这些500500字节需要15ms,使用快速方法在我的机器上需要0.5ms - YMMV,并注意到对于许多应用程序来说两者都足够快; - )。

最后,您可以将Array.CopyTo替换为static Array.Copy,低级Buffer.BlockCopy或带有预分配后备缓冲区的MemoryStream - 这些在我的测试中(x64 .NET 4.0),所有内容都完全相同。

答案 1 :(得分:4)

这是一个基于Andrew Bezzubfejesjoco's answers的解决方案,预先分配所需的所有内存。这产生Θ(N)内存使用和Θ(N)时间(N是总字节数)。

byte[] result = new byte[list.Sum(a => a.Length)];
using(var stream = new MemoryStream(result))
{
    foreach (byte[] bytes in list)
    {
        stream.Write(bytes, 0, bytes.Length);
    }
}
return result;

答案 2 :(得分:2)

将它们全部写入MemoryStream而不是列表。然后调用MemoryStream.ToArray()。或者当您有列表时,首先汇总所有字节数组长度,创建一个具有总长度的新字节数组,并将每个数组复制到大数组中的最后一个数组之后。

答案 3 :(得分:2)

使用Linq:

    List<byte[]> list = new List<byte[]>();
    list.Add(new byte[] { 1, 2, 3, 4 });
    list.Add(new byte[] { 1, 2, 3, 4 });
    list.Add(new byte[] { 1, 2, 3, 4 });

    IEnumerable<byte> result = Enumerable.Empty<byte>();

    foreach (byte[] bytes in list)
    {
        result = result.Concat(bytes);
    }

    byte[] newArray = result.ToArray();

可能更快的解决方案(不预先声明阵列):

IEnumerable<byte> bytesEnumerable = GetBytesFromList(list);

byte[] newArray = bytesEnumerable.ToArray();

private static IEnumerable<T> GetBytesFromList<T>(IEnumerable<IEnumerable<T>> list)
{
    foreach (IEnumerable<T> elements in list)
    {
        foreach (T element in elements)
        {
            yield return element;
        }
    }
}

上面似乎只会迭代每个数组一次。

答案 4 :(得分:0)

不是将每个字节数组存储到List<byte[]>,而是可以使用List<byte>方法将它们直接添加到{{1}}。

答案 5 :(得分:-1)

list.addrange怎么样?