如何在C#中有效地获取字节数组(前N个元素)的子集?

时间:2012-05-10 17:55:22

标签: c# .net

我有一个最大大小为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中。

5 个答案:

答案 0 :(得分:11)

Buffer.BlockCopy将是我的选择。

Microsoft示例: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);

答案 1 :(得分:6)

如果您无法更改方法签名,那么您就会陷入困境。您无法在类型为byte [] 的字节数组上创建“视图”。理想的解决方案是操作要么采用ArraySegment<byte>byte[],然后是偏移和计数。如果你真的无法改变Write方法,那么遗憾的是你不得不创建一个新数组并将数据复制到它。

答案 2 :(得分:3)

你无法做到这一点。 Array.Resize而不是更改数组的长度,只需将其复制到新的数组实例。

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

  

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

这符合您的需要,因为您有一个字节数组,而byte是基本类型。

答案 3 :(得分:3)

    byte[] b = new Byte[] {1, 2, 3, 4, 5};
    IEnumerable<Byte> middle = b.Skip(2).Take(3);

这应该让你得到你喜欢的任何中间部分。这很可能是副本,但我认为你不应该试图避免这种情况。

答案 4 :(得分:2)

如果方法签名为(byte[]),则除了复制之外,您无法执行任何操作。

如果您可以更改签名:

  • stream支持编写数组的子集,因此请求Stream.Write之类的签名并不罕见:

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

  • 另一个选项是传递IEnumerable<byte>,这样您就可以按照自己的方式切片,而无需复制。