首页 > 解决方案 > How to take array segments out of a byte array after every X step?

问题描述

I got a big byte array (around 50kb) and i need to extract numeric values from it. Every three bytes are representing one value. What i tried is to work with LINQs skip & take but it's really slow regarding the large size of the array.

This is my very slow routine:

List<int> ints = new List<int>();
for (int i = 0; i <= fullFile.Count(); i+=3)
{
    ints.Add(BitConverter.ToInt16(fullFile.Skip(i).Take(i + 3).ToArray(), 0));
}

I think i got a wrong approach to this.

标签: c#arrayslinq

解决方案


你的代码

首先,ToInt16只使用两个字节。所以你的第三个字节将被丢弃。

您不能使用ToInt32它,因为它会包含一个额外的字节。

让我们回顾一下:

fullFile.Skip(i).Take(i + 3).ToArray()

..仔细看看Take(i + 3)。它说你想复制一个越来越大的缓冲区。例如,when iis on index 32000 您将 32003 字节复制到新缓冲区中。

这就是代码很慢的原因。

代码也很慢,因为您分配了大量需要进行垃圾收集的字节缓冲区。65535 个大小不断增长的额外缓冲区,必须进行垃圾收集。

你也可以这样做:

List<int> ints = new List<int>();
var workBuffer = new byte[4];
for (int i = 0; i <= fullFile.Length; i += 3)
{
    // Copy the three bytes into the beginning of the temp buffer
    Buffer.BlockCopy(fullFile, i, workBuffer, 0, 3);

    // Now we can use ToInt32 as the last byte always is zero
    var value = BitConverter.ToInt32(workBuffer, 0);

    ints.Add(value);
}

很容易理解,但不是最快的代码。

更好的解决方案

所以最有效的方法是自己进行转换(位移)。

就像是:

List<int> ints = new List<int>();
for (int i = 0; i <= fullFile.Length; i += 3)
{
    // This code assume little endianess 
    var value = (fullFile[i + 2] << 16)
                + (fullFile[i + 1] << 8)
                + fullFile[i];
    ints.Add(value);
}

这段代码不分配任何额外的东西(除了整数),而且应该很快。

您可以在 MSDN中阅读有关Shift 运算符的更多信息。关于字节序


推荐阅读