【发布时间】:2017-10-17 13:40:13
【问题描述】:
我正在阅读一种专有的二进制数据文件格式。格式基本上是 header, data, size_of_previous_data, header, data, size_of_previous_data, header, data, size_of_previous_data, ... 标头的一部分包括下一个数据块的字节数以及紧随数据后列出的大小。标头为 256 字节,数据通常约为 2MB,size_of_previous_data 是 32 位整数。
文件一般都很大~GB,我经常要在几十个文件中搜索我想要的数据。为了做到这一点,我在代码中做的第一件事是 idex 每个文件,即只读取标题并记录相关数据的位置(文件和字节数)。我的代码基本上使用 fstream::read() 准备好标头,检查数据大小,使用 fstream::seekg() 跳过数据,然后读入 size_of_previous_data,然后重复直到我到达文件末尾。
我的问题是这个索引非常缓慢。数据位于我的 Windows 10 笔记本电脑的内部 7200 rpm 硬盘驱动器上,任务管理器显示我的硬盘驱动器使用率已达到极限,但我的读取速度仅为 1.5 MB/s,响应时间通常 > 70 ms。我正在使用 std::fstream 读取文件,使用 fstream::get() 读取标题并使用 fstream::seekg() 移动到下一个标题。
我已经分析了我的代码,几乎所有时间都花在 fstream::read() 代码中以读取 size_of_previous_data 值。我假设当我这样做时,紧随其后的数据会被缓冲,因此我的 fstream::read() 获取下一个标头几乎不需要时间。
所以我想知道是否有办法优化这个?几乎我在任何缓冲读取中的整个缓冲区都可能被浪费(如果是 8kB 缓冲区,则其中的 97%)。有没有办法缩小它,是否值得(也许底层操作系统缓冲区也以我无法更改的方式)?
【问题讨论】:
-
为什么不把开头的文件都读一遍呢? GB 的 RAM 通常没问题,但搜索 GB 大小的文件很慢也不足为奇
-
如果数据的大小已经存储在标头中,为什么在查找数据时不跳过
size_of_previous_data?您可以保存读取,直到您需要读取数据本身,然后将其用作一种校验和。如果您一次只读取 256 个字节,那么您不需要比这更大的缓冲区。 -
如果您的操作系统支持,请尝试内存映射您的文件。操作系统将为您处理将块读取到内存中。
-
@tobi303 目前我需要读取的文件总大小为 11 GB,但我目前正在处理测试数据,这将很快增加到 44 GB,甚至更多。我的笔记本电脑有 8 GB 内存,所以我通过阅读所有内容来做的就是让我猜想引起抖动。
-
@ThomasMatthews 内存映射可能会明显更快吗?还是它会完全按照我在幕后所做的那样做?这是我问题的症结所在。我在问是否有人已经知道这样做的好策略,或者我是否需要花费大量时间测试内存映射之类的东西,并且可能会发现性能没有明显变化。