在C#中追加两个或更多字节数组

时间:2009-05-21 20:58:44

标签: c# bytearray

是否有最好的(见下文)方法在C#中附加两个字节数组?

假装我完全控制,我可以使第一个字节数组足够大,以便在结尾保存第二个字节数组,并使用Array.CopyTo函数。或者我可以遍历各个字节并进行分配。

有更好的方法吗?我无法想象做一些事情,比如将字节数组转换为字符串并加入它们并将它们转换回来将比上述任何一种方法都好。

就最佳/更好(按顺序)而言:

  1. 最快
  2. 最少RAM消耗
  3. 一个限制是我必须在.NET 2.0框架中工作。

    推荐的两个选择是MemoryStream和BlockCopy。我已经对10,000,000次循环进行了3次简单的速度测试,得到了以下结果:

    以毫秒为单位的10,000次循环的3次运行的平均值:

    • BlockCopy时间:1154 ,范围为13毫秒
    • MemoryStream GetBuffer时间:1470,范围为14毫秒
    • MemoryStream ToArray时间:1895,范围为3毫秒
    • CopyTo Time:2079,范围为19毫秒
    • 逐字节时间:2203,范围为10毫秒

    List< byte>的结果AddRange超过1000万个循环: 列表与LT;字节>时间:16694

    相对RAM消耗(1表示基线,更高表示更差):

    • 逐字节:1
    • BlockCopy:1
    • 复制到:1
    • MemoryStream GetBuffer:2.3
    • MemoryStream ToArray:3.3
    • 列出< byte>:4.2

    测试表明,一般情况下,除非你做了很多字节副本[],否则查看字节副本不值得关注[例如1000万次运行产生的差异高达1.1秒]。

8 个答案:

答案 0 :(得分:24)

您需要BlockCopy

根据this blog post,它比Array.CopyTo快。

答案 1 :(得分:14)

您还可以使用MemoryStream的方法。假设b1和b2是两个字节的数组,你可以通过以下方式使用MemoryStream获得一个新的数组b3:

var s = new MemoryStream();
s.Write(b1, 0, b1.Length);
s.Write(b2, 0, b2.Length);
var b3 = s.ToArray();

这应该在没有LINQ的情况下工作,实际上要快得多。

答案 2 :(得分:11)

创建一个新的MemoryStream,在构造函数中传递一个与合并的缓冲区完全相同的缓冲区。编写单个数组,最后使用缓冲区:

byte[] deadBeef = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF};
byte[] baadF00d = new byte[] { 0xBA, 0xAD, 0xF0, 0x0D};
int newSize = deadBeef.Length + baadF00d.Length;
var ms = new MemoryStream(new byte[newSize], 0, newSize, true, true);
ms.Write(deadBeef, 0, deadBeef.Length);
ms.Write(baadF00d, 0, baadF00d.Length);
byte[] merged = ms.GetBuffer();

.NET中的许多低级I / O函数都采用字节数组和偏移量。这样做是为了防止不必要的副本。如果这对性能敏感,请确保您确实需要合并数组,否则只需使用缓冲区和偏移量。

答案 3 :(得分:6)

另一个选择,虽然我没有测试它以了解它在速度和内存消耗方面的表现如何,但是LINQ方法是这样的:

byte[] combined = bytesOne.Concat(bytesTwo).Concat(bytesThree).ToArray();

...其中bytesOne,bytesTwo和bytesThree是字节数组。由于Concat使用延迟执行,因此不应创建任何中间数组,并且在最终构造最终合并数组之前,它不应复制原始数组。

编辑:LINQBridge将允许您在2.0框架中使用LINQ-to-Objects(这是一个示例)。我明白,如果你不想依赖这个,但这是一个选择。

答案 4 :(得分:3)

如果您的阵列大小会不时发生变化,那么您最好先使用List<T>。然后,您只需调用列表的AddRange()方法即可。

否则,Array.Copy()或Array.CopyTo()与您可能看到的任何其他内容一样好。

答案 5 :(得分:2)

您是否需要输出实际上是一个字节数组?

如果没有,你可以创建一个“智能游标”(类似于LINQ所做的):创建一个自定义的IEnumerator&lt; byte&gt;这将首先迭代第一个数组,然后继续第二个数组而不会中断。

这可以在2.0框架中快速运行(因为数组的连接几乎没有成本),并且不使用比阵列已经消耗的更多的RAM。

答案 6 :(得分:2)

您是否教过使用List或ArrayList而不是Array?使用这些类型,它们可以增长或缩小,并通过InsertRange

追加

答案 7 :(得分:0)

您的第一个选项是使第一个数组足够大以包含第二个数组并使用Array.CopyTo最终与手动迭代每个项目并进行分配大致相同。 Array.CopyTo()只是让它更简洁。

与上述相比,转换为字符串并返回到数组将会非常慢。并且可能会使用更多内存。