3

我的程序需要从一个随机访问的巨大二进制文件中读取块。我有一个可能有几千个条目的偏移量和长度列表。用户选择一个条目,程序寻找偏移量并读取长度字节。

该程序在内部使用 TMemoryStream 来存储和处理从文件中读取的块。读取数据是通过 TFileStream 完成的,如下所示:

FileStream.Position := Offset;
MemoryStream.CopyFrom(FileStream, Size);

这工作正常,但不幸的是,随着文件变大,它变得越来越慢。文件大小从几兆字节开始,但经常达到几十千兆字节。读取的块大小约为 100 KB。

该文件的内容只能由我的程序读取。它是当时唯一访问该文件的程序。文件也存储在本地,因此这不是网络问题。

我在 Windows XP 机器上使用 Delphi 2007。

我能做些什么来加快这个文件的访问速度?

编辑:

  • 无论读取文件的哪个部分,大文件的文件访问都很慢。
  • 程序通常不会顺序读取文件。块的顺序是用户驱动的,无法预测。
  • 从大文件中读取块总是比从小文件中读取同样大的块要慢。
  • 我说的是从文件中读取块的性能,而不是处理整个文件所需的总时间。对于较大的文件,后者显然需要更长的时间,但这不是这里的问题。

我需要向大家道歉:在我按照建议使用内存映射文件实现文件访问之后,结果证明它并没有太大的区别。但是在我添加了更多的计时代码之后,结果也证明不是文件访问会减慢程序的速度。无论文件大小如何,文件访问实际上都需要几乎恒定的时间。用户界面的某些部分(我尚未确定)似乎存在大量数据的性能问题,并且不知何故,当我第一次对流程进行计时时,我没有看到差异。

我很抱歉在确定瓶颈方面草率。

4

3 回答 3

3

如果您打开CreateFile () WinAPI 函数的帮助主题,您会在那里找到有趣的标志,例如 FILE_FLAG_NO_BUFFERING 和 FILE_FLAG_RANDOM_ACCESS 。你可以和他们一起玩以获得一些性能。

接下来,复制文件数据,即使是 100Kb 大小,也是一个额外的步骤,会减慢操作速度。使用CreateFileMapping和 MapViewOfFile 函数来获取指向数据的准备使用指针是一个好主意。这样您就可以避免复制并且还可能获得某些性能优势(但您需要仔细测量速度)。

于 2011-01-06T13:32:04.630 回答
0

Delphi 中的股票 TMemoryStream 由于其分配内存的方式而运行缓慢。NexusDB 公司拥有效率更高的 TnxMemoryStream。那里可能有一些免费的,效果更好。

库存的 Delphi TFileStream 也不是最有效的组件。历史上的回溯 Julian Bucknall 在杂志或其他可以非常有效地处理文件流的地方发布了一个名为 BufferedFileStream 的组件。

祝你好运。

于 2011-01-08T01:09:59.857 回答
0

也许你可以采取这种方法:

对 max fileposition 上的条目进行排序,然后按以下顺序排序:

  1. 取只需要文件前 X MB 的条目(直到某个文件位置)
  2. 从文件中读取 X MB 到缓冲区(TMemorystream
  3. 现在从缓冲区中读取条目(可能是多线程的)
  4. 对所有条目重复此操作。

简而言之:缓存文件的一部分并读取适合它的所有条目(多线程),然后缓存下一部分等。

如果您只采用原来的方法,但按位置对条目进行排序,也许您可​​以获得速度。

于 2011-01-06T14:30:22.040 回答