Best way to combine two or more byte arrays in C#
我在C#中有3个字节数组,需要组合成一个。 什么是完成此任务的最有效方法?
对于基本类型(包括字节),请使用
我对每个建议的方法进行了计时,分别使用3个10字节的数组,执行了100万次循环。结果如下:
我将每个数组的大小增加到100个元素,然后重新运行测试:
我将每个数组的大小增加到1000个元素,然后重新运行测试:
最后,我将每个数组的大小增加到一百万个元素,然后重新运行测试,每个循环仅执行4000次:
因此,如果您需要一个新的字节数组,请使用
1 2 3 4 | byte[] rv = new byte[a1.Length + a2.Length + a3.Length]; System.Buffer.BlockCopy(a1, 0, rv, 0, a1.Length); System.Buffer.BlockCopy(a2, 0, rv, a1.Length, a2.Length); System.Buffer.BlockCopy(a3, 0, rv, a1.Length + a2.Length, a3.Length); |
但是,如果可以使用
1 | IEnumerable<byte> rv = a1.Concat(a2).Concat(a3); |
如果您具有任意数量的数组,并且正在使用.NET 3.5,则可以使
1 2 3 4 5 6 7 8 9 10 | private byte[] Combine(params byte[][] arrays) { byte[] rv = new byte[arrays.Sum(a => a.Length)]; int offset = 0; foreach (byte[] array in arrays) { System.Buffer.BlockCopy(array, 0, rv, offset, array.Length); offset += array.Length; } return rv; } |
*注意:上面的代码块要求您在顶部添加以下名称空间才能起作用。
1 | using System.Linq; |
就Jon Skeet关于后续数据结构的迭代(字节数组与IEnumerable
关键是,了解创建数据结构的效率和使用结果的结构非常重要。仅关注创作的效率可能会忽略与使用相关的效率低下。乔恩·库德斯
在我看来,许多答案都忽略了上述要求:
- 结果应该是一个字节数组
- 它应该尽可能高效
这两个一起排除了LINQ字节序列-带有
如果当然不是真正的要求,则LINQ可能是一个很好的解决方案(或
(编辑:我刚刚有了另一种想法。在复制数组和延迟读取它们之间存在很大的语义差异。请考虑一下,如果在调用
这是我提出的方法-与其他答案中包含的方法非常相似,当然:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public static byte[] Combine(byte[] first, byte[] second) { byte[] ret = new byte[first.Length + second.Length]; Buffer.BlockCopy(first, 0, ret, 0, first.Length); Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); return ret; } public static byte[] Combine(byte[] first, byte[] second, byte[] third) { byte[] ret = new byte[first.Length + second.Length + third.Length]; Buffer.BlockCopy(first, 0, ret, 0, first.Length); Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); Buffer.BlockCopy(third, 0, ret, first.Length + second.Length, third.Length); return ret; } public static byte[] Combine(params byte[][] arrays) { byte[] ret = new byte[arrays.Sum(x => x.Length)]; int offset = 0; foreach (byte[] data in arrays) { Buffer.BlockCopy(data, 0, ret, offset, data.Length); offset += data.Length; } return ret; } |
当然," params"版本需要首先创建一个字节数组数组,这会带来额外的效率低下。
为了使代码更整洁,我将Matt的LINQ示例更进一步:
1 | byte[] rv = a1.Concat(a2).Concat(a3).ToArray(); |
就我而言,数组很小,因此我不关心性能。
如果您只需要一个新的字节数组,请使用以下命令:
1 2 3 4 5 6 7 8 | byte[] Combine(byte[] a1, byte[] a2, byte[] a3) { byte[] ret = new byte[a1.Length + a2.Length + a3.Length]; Array.Copy(a1, 0, ret, 0, a1.Length); Array.Copy(a2, 0, ret, a1.Length, a2.Length); Array.Copy(a3, 0, ret, a1.Length + a2.Length, a3.Length); return ret; } |
另外,如果只需要一个IEnumerable,请考虑使用C#2.0 yield操作符:
1 2 3 4 5 6 7 8 9 | IEnumerable<byte> Combine(byte[] a1, byte[] a2, byte[] a3) { foreach (byte b in a1) yield return b; foreach (byte b in a2) yield return b; foreach (byte b in a3) yield return b; } |
我实际上在使用Concat时遇到了一些问题...(数组在1000万中,实际上崩溃了)。
我发现以下内容很简单,容易并且可以很好地工作而不会崩溃,并且它适用于任意数量的数组(不只是三个)(它使用LINQ):
1 2 3 4 | public static byte[] ConcatByteArrays(params byte[][] arrays) { return arrays.SelectMany(x => x).ToArray(); } |
memorystream类对我来说做得很好。我无法使缓冲区类像内存流一样快地运行。
1 2 3 4 5 6 | using (MemoryStream ms = new MemoryStream()) { ms.Write(BitConverter.GetBytes(22),0,4); ms.Write(BitConverter.GetBytes(44),0,4); ms.ToArray(); } |
1 2 3 4 5 6 7 8 | public static byte[] Concat(params byte[][] arrays) { using (var mem = new MemoryStream(arrays.Sum(a => a.Length))) { foreach (var array in arrays) { mem.Write(array, 0, array.Length); } return mem.ToArray(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public static bool MyConcat< T >(ref T[] base_arr, ref T[] add_arr) { try { int base_size = base_arr.Length; int size_T = System.Runtime.InteropServices.Marshal.SizeOf(base_arr[0]); Array.Resize(ref base_arr, base_size + add_arr.Length); Buffer.BlockCopy(add_arr, 0, base_arr, base_size * size_T, add_arr.Length * size_T); } catch (IndexOutOfRangeException ioor) { MessageBox.Show(ioor.Message); return false; } return true; } |
可以使用泛型来组合数组。以下代码可以轻松扩展为三个数组。这样,您无需为不同类型的数组重复代码。以上某些答案对我来说似乎过于复杂。
1 2 3 4 5 6 7 | private static T[] CombineTwoArrays< T >(T[] a1, T[] a2) { T[] arrayCombined = new T[a1.Length + a2.Length]; Array.Copy(a1, 0, arrayCombined, 0, a1.Length); Array.Copy(a2, 0, arrayCombined, a1.Length, a2.Length); return arrayCombined; } |
这是@Jon Skeet提供的答案的概括。
它基本相同,只是可用于任何类型的数组,而不仅限于字节:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public static T[] Combine< T >(T[] first, T[] second) { T[] ret = new T[first.Length + second.Length]; Buffer.BlockCopy(first, 0, ret, 0, first.Length); Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); return ret; } public static T[] Combine< T >(T[] first, T[] second, T[] third) { T[] ret = new T[first.Length + second.Length + third.Length]; Buffer.BlockCopy(first, 0, ret, 0, first.Length); Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); Buffer.BlockCopy(third, 0, ret, first.Length + second.Length, third.Length); return ret; } public static T[] Combine< T >(params T[][] arrays) { T[] ret = new T[arrays.Sum(x => x.Length)]; int offset = 0; foreach (T[] data in arrays) { Buffer.BlockCopy(data, 0, ret, offset, data.Length); offset += data.Length; } return ret; } |
您只需要传递字节数组列表,此函数将为您返回字节数组(合并)。
这是我认为最好的解决方案:)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public static byte[] CombineMultipleByteArrays(List<byte[]> lstByteArray) { using (var ms = new MemoryStream()) { using (var doc = new iTextSharp.text.Document()) { using (var copy = new PdfSmartCopy(doc, ms)) { doc.Open(); foreach (var p in lstByteArray) { using (var reader = new PdfReader(p)) { copy.AddDocument(reader); } } doc.Close(); } } return ms.ToArray(); } } |
康卡特是正确的答案,但由于某种原因,手动操作获得了最多的选票。如果您喜欢该答案,也许您会更希望此更通用的解决方案:
1 2 3 4 5 6 | IEnumerable<byte> Combine(params byte[][] arrays) { foreach (byte[] a in arrays) foreach (byte b in a) yield return b; } |
这会让您执行以下操作: