我正在创建多个字节数组,需要将它们拼接在一起形成一个大的字节数组 - 我不想使用byte[]数组,但在这里别无选择...
我创建每个字节数组时都会将其添加到列表中,因此只有在获取所有byte[]后才需要进行合并,但我的问题是,实际上最好的方法是什么?
当我有一个包含未知数量byte[]的列表并且我想要将它们全部连接在一起时。
谢谢。
我正在创建多个字节数组,需要将它们拼接在一起形成一个大的字节数组 - 我不想使用byte[]数组,但在这里别无选择...
我创建每个字节数组时都会将其添加到列表中,因此只有在获取所有byte[]后才需要进行合并,但我的问题是,实际上最好的方法是什么?
当我有一个包含未知数量byte[]的列表并且我想要将它们全部连接在一起时。
谢谢。
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;
}
或者像马丁诺建议的那样:
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();
在我的机器上,使用短方法将这500500字节连接起来需要15毫秒,而使用快速方法只需要0.5毫秒- YMMV,并且请注意,对于许多应用程序,两种方法都足够快;-)。
最后,您可以使用静态的Array.Copy
、底层的Buffer.BlockCopy
或预分配的后备缓冲区MemoryStream
来替换Array.CopyTo
- 在我的测试中它们的性能几乎相同(x64 .NET 4.0)。
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;
使用 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;
}
}
}
将它们全部写入MemoryStream而不是列表。然后调用MemoryStream.ToArray()。或者当您拥有列表时,首先总结所有字节数组的长度,创建一个新的字节数组,并在大数组中将每个数组复制到最后一个之后。