【问题标题】:How do I efficiently get a subset of a byte array (first N elements) in C#?如何在 C# 中有效地获取字节数组的子集(前 N 个元素)?
【发布时间】:2012-05-10 17:55:21
【问题描述】:

我有一个最大大小为 1K 的字节数组缓冲区。我想写出数组的一个子集(子集的开头总是元素 0,但我们感兴趣的长度在一个变量中)。

这里的应用是压缩。我将缓冲区传递给压缩函数。为简单起见,假设压缩将产生等于或小于 1K 字节的数据。

byte[] buffer = new byte[1024];
while (true)
{
    uncompressedData = GetNextUncompressedBlock();
    int compressedLength = compress(buffer, uncompressedData);

    // Here, compressedBuffer[0..compressedLength - 1] is what we're interested in

    // There's a method now with signature Write(byte[] compressedData) that
    // I won't be able to change. Short of allocating a custom sized buffer,
    // and copying data into the custom sized buffer... is there any other
    // technique I could use to only expose the data I want?
}

我真的很想避免在这里复制——这似乎完全没有必要,因为所需的所有数据都已经在 buffer 中了。

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    Buffer.BlockCopy 是我的选择。

    微软示例:http://msdn.microsoft.com/en-us/library/system.buffer.blockcopy.aspx

    const int INT_SIZE = 4;
    int[] arr = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
    Buffer.BlockCopy(arr, 3 * INT_SIZE, arr, 0 * INT_SIZE, 4 * INT_SIZE);
    foreach (int value in arr)
       Console.Write("{0}  ", value);
    // The example displays the following output:
    //       8  10  12  14  10  12  14  16  18  20 
    

    您的代码如下所示:

    uncompressedData = GetNextUncompressedBlock();      
    int compressedLength = compress(buffer, uncompressedData);
    Buffer.BlockCopy(buffer, 0, buffer, 0, compressedLength);
    

    【讨论】:

      【解决方案2】:

      如果您无法更改方法签名,那么您将陷入困境。您不能在字节数组上创建“视图”类型为 byte[]。理想的解决方案是让操作采用 ArraySegment<byte>byte[] 后跟偏移量和计数。如果您真的无法更改 Write 方法,那么不幸的是,您只能创建一个新数组并将数据复制到其中。

      【讨论】:

      • 哇,你以前用 WCF 帮助过我(作为不同的用户)。再次感谢 Carlos +1 的提示。
      【解决方案3】:
          byte[] b = new Byte[] {1, 2, 3, 4, 5};
          IEnumerable<Byte> middle = b.Skip(2).Take(3);
      

      这应该可以让您获得您喜欢的任何中间部分。这很可能会复制,但我认为您不应该尝试避免这种情况。

      【讨论】:

        【解决方案4】:

        你没有办法做到这一点。 Array.Resize 无需更改数组的长度,只需将其复制到新的数组实例即可。

        但是,您可以使用性能更好的Buffer class

        Buffer 提供了将字节从一个原始类型数组复制到另一个原始类型数组、从数组中获取字节、在数组中设置字节以及获取数组长度的方法。与 System.Array 类中的类似方法相比,此类在操作原始类型方面提供了更好的性能。

        这符合你的需要,因为你有一个字节数组,而 byte 是一个原始类型。

        【讨论】:

          【解决方案5】:

          如果方法签名是(byte[]),则只能复制。

          如果您可以更改签名:

          • 流支持写入数组的子集,因此请求具有类似Stream.Write 的签名并不罕见:

            public abstract void Write( byte[] buffer, int offset, int count)

          • 另一种选择是传递IEnumerable&lt;byte&gt;,这样您就可以根据需要对数组进行切片,而无需复制。

          【讨论】:

            猜你喜欢
            • 2012-02-16
            • 2016-04-25
            • 2011-04-12
            • 1970-01-01
            • 2010-09-24
            • 2020-07-22
            • 1970-01-01
            • 2023-04-01
            相关资源
            最近更新 更多