【问题标题】:Read giant int-Array from binary file从二进制文件中读取巨大的 int-Array
【发布时间】:2014-11-02 14:33:27
【问题描述】:

任务

我有一个包含整数的大文件(大约 20 GB),我想用 C# 读取它们。

简单的方法

将文件读入内存(读入字节数组)非常快(使用 SSD,整个文件都可以放入内存)。但是,当我使用二进制读取器(通过内存流)读取这些字节时,ReadInt32 方法比将文件读取到内存所需的时间要长得多。我预计磁盘 IO 会成为瓶颈,但这是转换!

想法和问题

有没有办法直接将整个字节数组转换成一个整数数组,而不必使用 ReadInt32 方法一个接一个地转换它?

class Program
{
    static int size = 256 * 1024 * 1024;
    static string filename = @"E:\testfile";

    static void Main(string[] args)
    {
        Write(filename, size);
        int[] result = Read(filename, size);
        Console.WriteLine(result.Length);
    }

    static void Write(string filename, int size)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        BinaryWriter bw = new BinaryWriter(new FileStream(filename, FileMode.Create), Encoding.UTF8);
        for (int i = 0; i < size; i++)
        {
            bw.Write(i);
        }
        bw.Close();
        stopwatch.Stop();
        Console.WriteLine(String.Format("File written in {0}ms", stopwatch.ElapsedMilliseconds));
    }

    static int[] Read(string filename, int size)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        byte[] buffer = File.ReadAllBytes(filename);
        BinaryReader br = new BinaryReader(new MemoryStream(buffer), Encoding.UTF8);
        stopwatch.Stop();
        Console.WriteLine(String.Format("File read into memory in {0}ms", stopwatch.ElapsedMilliseconds));
        stopwatch.Reset();
        stopwatch.Start();

        int[] result = new int[size];

        for (int i = 0; i < size; i++)
        {
            result[i] = br.ReadInt32();
        }
        br.Close();
        stopwatch.Stop();
        Console.WriteLine(String.Format("Byte-array casted to int-array in {0}ms", stopwatch.ElapsedMilliseconds));

        return result;
    }
}
  • 文件写入时间为 5499 毫秒
  • 文件在 455 毫秒内读入内存
  • 字节数组在 3382 毫秒内转换为整数数组

【问题讨论】:

  • 您最终必须执行转换。您可以将数组读入内存并根据需要使用 BitConverter 从数组中获取值吗?
  • @PatrickHofman:看来他已经知道如何将文件读入内存了。
  • Golly 20GB 可能一口气读完很多。您是否需要一次坐下所有这些。否则我首先想到的是内存映射文件,但默认情况下这是非托管代码。
  • 人们有点困惑。您为什么不向我们展示您目前拥有的代码?

标签: c# performance casting binary


【解决方案1】:

您可以分配一个大小合适的临时byte[] 缓冲区,并使用Buffer.BlockCopy 方法将字节增量复制到int[] 数组。

BinaryReader reader = ...;
int[] hugeIntArray = ...;

const int TempBufferSize = 4 * 1024 * 1024;
byte[] tempBuffer = reader.ReadBytes(TempBufferSize);
Buffer.BlockCopy(tempBuffer, 0, hugeIntArray, offset, TempBufferSize);

其中offset 是目标hugeIntArray 数组中的当前(对于当前迭代)起始索引。

【讨论】:

  • ReadBytes 可能会遭受同样的命运,尽管我不确定。
  • 我首先使用 ReadAllBytes 将整个文件读入内存。
  • 这明显更快:文件在 439 毫秒内读入内存,字节数组在 105 毫秒内转换为 int-array
猜你喜欢
  • 1970-01-01
  • 2013-04-07
  • 2015-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
相关资源
最近更新 更多