我在c#中有3个字节数组,我需要合并成一个。完成这项任务最有效的方法是什么?


当前回答

所有你需要传递的字节数组列表和这个函数将返回你的字节数组(合并)。 这是我认为最好的解决方案:)。

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

其他回答

对于基元类型(包括字节),使用System.Buffer.BlockCopy而不是System.Array.Copy。这是更快。

我在循环中对每个建议的方法进行计时,每个方法使用3个10字节的数组执行了100万次。以下是调查结果:

使用System.Array.Copy创建字节数组- 0.2187556秒 使用System.Buffer.BlockCopy创建字节数组- 0.1406286秒 IEnumerable<字节>使用c# yield运算符- 0.0781270秒 IEnumerable<byte> using LINQ's Concat<> - 0.0781270秒

我将每个数组的大小增加到100个元素,并重新运行测试:

使用System.Array.Copy创建字节数组- 0.2812554秒 使用System.Buffer.BlockCopy创建字节数组- 0.2500048秒 IEnumerable<字节>使用c# yield运算符- 0.0625012秒 IEnumerable<byte> using LINQ's Concat<> - 0.0781265秒

我将每个数组的大小增加到1000个元素,并重新运行测试:

使用System.Array.Copy创建字节数组- 1.0781457秒 使用System.Buffer.BlockCopy创建字节数组1.0156445秒 IEnumerable<字节>使用c# yield运算符- 0.0625012秒 IEnumerable<byte> using LINQ's Concat<> - 0.0781265秒

最后,我将每个数组的大小增加到100万个元素,并重新运行测试,每个循环只执行4000次:

使用System.Array.Copy创建字节数组- 13.4533833秒 使用System.Buffer.BlockCopy创建字节数组 IEnumerable<字节>使用c# yield操作符- 0秒 IEnumerable<字节>使用LINQ的Concat<> - 0秒

所以,如果你需要一个新的字节数组,使用

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

但是,如果你可以使用IEnumerable<byte>,肯定更喜欢LINQ的Concat<>方法。它只比c#的yield操作符稍慢,但更简洁、更优雅。

IEnumerable<byte> rv = a1.Concat(a2).Concat(a3);

如果你有任意数量的数组,并且使用。net 3.5,你可以让System.Buffer.BlockCopy解决方案更通用,像这样:

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

*注意:上面的块需要您在顶部添加以下命名空间才能工作。

using System.Linq;

对于Jon Skeet关于后续数据结构迭代(字节数组vs. IEnumerable<byte>)的观点,我重新运行了最后一次计时测试(100万个元素,4000次迭代),添加了一个循环,每次迭代整个数组:

使用System.Array.Copy新建字节数组- 78.20550510秒 使用System.Buffer.BlockCopy创建字节数组77.89261900秒 IEnumerable<字节>使用c# yield运算符- 551.7150161秒 IEnumerable<byte> using LINQ's Concat<> - 448.1804799秒

重点是,理解创建结果数据结构和使用结果数据结构的效率是非常重要的。仅仅关注创造的效率可能会忽略与使用相关的低效率。荣誉,乔恩。

memorystream类为我很好地完成了这项工作。我无法让缓冲类运行得像内存流一样快。

using (MemoryStream ms = new MemoryStream())
{
  ms.Write(BitConverter.GetBytes(22),0,4);
  ms.Write(BitConverter.GetBytes(44),0,4);
  ms.ToArray();
}

实际上,我在使用Concat时遇到了一些问题…(对于1000万个数组,它实际上崩溃了)。

我发现以下是简单,容易,工作得很好,没有崩溃对我来说,它适用于任何数量的数组(不仅仅是三个)(它使用LINQ):

public static byte[] ConcatByteArrays(params byte[][]  arrays)
{
    return arrays.SelectMany(x => x).ToArray();
}
    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;
    }

我以Matt的LINQ为例,进一步提高了代码的洁净度:

byte[] rv = a1.Concat(a2).Concat(a3).ToArray();

在我的例子中,数组很小,所以我不关心性能。