从 byte[] 中提取可变宽度有符号整数的最快方法



标题不言自明。我有一个文件,其中包含可变宽度整数的base64编码byte[],最小8位,最大32位

有一个大文件(48MB),我正在尝试找到从流中抓取整数的最快方法。

这是来自 perf 应用程序的最快代码:

static int[] Base64ToIntArray3(string base64, int size)
{
    List<int> res = new List<int>();
    byte[] buffer = new byte[4];
    using (var ms = new System.IO.MemoryStream(Convert.FromBase64String(base64)))
    {
        while(ms.Position < ms.Length)
        {
            ms.Read(buffer, 0, size);
            res.Add(BitConverter.ToInt32(buffer, 0));
        }
    }
    return res.ToArray();
}

我看不到将字节填充到 32 位的更快方法。有什么想法,小伙子和小伙子吗?解决方案应使用 C#。如果必须,我可以下降到 C/++,但我不想。

没有理由使用内存流将字节从一个数组移动到另一个数组,只需直接从数组中读取即可。此外,数组的大小是已知的,因此需要将项目添加到列表中,然后将其转换为数组,您可以从一开始就使用数组:

static int[] Base64ToIntArray3(string base64, int size) {
  byte[] data = Convert.FromBase64String(base64);
  int cnt = data.Length / size;
  int[] res = new int[cnt];
  for (int i = 0; i < cnt; i++) {
    switch (size) {
      case 1: res[i] = data[i]; break;
      case 2: res[i] = BitConverter.ToInt16(data, i * 2); break;
      case 3: res[i] = data[i * 3] + data[i * 3 + 1] * 256 + data[i * 3 + 2] * 65536; break;
      case 4: res[i] = BitConverter.ToInt32(data, i * 4); break;
    }
  }
  return res;
}

注意:未经测试的代码!你必须验证它是否确实做了它应该做的事情,但至少它显示了原理。

这可能是我会这样做的。不使用流应该可以提高性能。这似乎是使用 Linq 应该很容易做到的事情,但我无法弄清楚。

    static int[] Base64ToIntArray3(string base64, int size)
    {
        if (size < 1 || size > 4) throw new ArgumentOutOfRangeException("size");
        byte[] data = Convert.FromBase64String(base64);
        List<int> res = new List<int>();
        byte[] buffer = new byte[4];
        for (int i = 0; i < data.Length; i += size )
        {
            Buffer.BlockCopy(data, i, buffer, 0, size);
            res.Add(BitConverter.ToInt32(buffer, 0));
        }
        return res.ToArray();
    }
好的,

所以我相信这是Linq的方法:

    static int[] Base64ToIntArray3(string base64, int size)
    {
        byte[] data = Convert.FromBase64String(base64);
        return data.Select((Value, Index) => new { Value, Index })
                   .GroupBy(p => p.Index / size)
                   .Select(g => BitConverter.ToInt32(g.Select(p => p.Value).Union(new byte[4 - size]).ToArray(), 0))
                   .ToArray();
    }

最新更新