【发布时间】:2018-05-01 15:03:17
【问题描述】:
假设我正在解析一个二进制记录文件。该文件可以包含任意数量的记录。格式为:
- 12 字节 C 字符串
- 4 字节长度
- 4 字节偏移
我打算使用fread() 从文件中获取记录,并将它们转换为内部数据结构。据我了解,fread() 在数据文件上拥有自己的内部缓冲区,以减少小读取的硬盘访问。
所以有两种选择:
- 循环:使用
fread()一次读取20个字节并解析它。这很简单,但缺点是我在每个循环中都对fread()进行函数调用。它不像系统调用那么糟糕,但它仍然每 20 个字节产生开销。在另一种极端情况下(例如,一次一个字节的文件解压缩)我可能会执行一个函数调用每个字节。 - 使用
fread()一次读取一个大块,然后循环:一次遍历我的副本20个字节,并解析它。解析本地内存很快,但这有一个缺点,即我正在“缓冲一个缓冲区”——即填充内部的fread()缓冲区,这样我就可以转身并将memcpy()它转到另一个结构。此外,这有点乏味 - 要么我必须自己将整个文件放入 RAM,要么我必须管理自己的缓冲区填充和刷新例程来分块读取文件。
所以我在这里有点纠结,因为理论上这两种解决方案似乎都不是最优的!
我的问题是:是否有任何使用顺序文件 IO 的模式可以避免这两个这些缺点?(请不要“仅分析它”cmets -问题不是“哪个更好”而是“是否有第三种选择”)
【问题讨论】:
-
“第三种选择”取决于操作系统,例如
mmap()在 POSIX 系统上。如果你想坚持使用 C stdio,只需使用简单的方法,让 stdio 处理缓冲。 -
引用:
no "just profile it" comments为什么不呢?您可能正在“发明”一个不真实的问题。您可能会发现,与磁盘访问时间相比,您在 SW 中所做的任何事情都无关紧要。在现代系统中几乎不可能猜测性能。 -
第四个选择是使用
read并管理你自己的缓冲区。 -
@melpomene 也依赖于操作系统(我猜你的意思是 POSIX 函数
read()) -
了解 setvbuf 和 _IONBF,然后使用 fread。
标签: c optimization io fread stdio