【问题标题】:How to read a large, and growing, file efficiently如何有效地读取大型且不断增长的文件
【发布时间】:2020-10-21 16:41:54
【问题描述】:

现有应用程序在运行时不断写入输出文件。我希望能够在另一个 (C++) 应用程序中逐行读取此文件以进行外部处理。

一个现实的场景是现有应用程序已经运行了一段时间。我的新应用程序启动并通过输出文件工作,“赶上”最近的条目。然后等待新行写入文件。

我确实不需要 需要解析整个文件,只需逐行读取它 - 它不是 XML 或 JSON 或类似的东西。由于文件可能非常大,我绝对不想将其全部加载到内存中。自从我在 C++ 中从事低级文件访问以来已经有很长时间了,所以我的问题是:

  • 标准文件 API 是否允许我读取文件而不将其缓存在内存中,如果可以,我该如何控制?
  • 是否需要特别注意读取正在写入的文件?

我知道这可以在操作系统级别完成,但我不确定这是如何通过标准库中的 C++ API 公开的。

【问题讨论】:

  • 这能回答你的问题吗? Implement "tail -f" in C++
  • 你想对文件做什么?逐行阅读但不解析 - 你会丢弃这些行吗?目前尚不清楚最终目标是什么。
  • 只要写作应用创建具有写入权限和读取共享的文件,而阅读应用以只读访问权限打开文件,您应该可以。就我而言,我有一个写入日志文件的服务,以及一个实时显示日志的查看器。我使用文件的内存映射视图来快速访问数据,并让服务在写入新数据时通知查看器,以便查看器可以映射和显示它,但在这种情况下,这些不是严格要求。
  • @SergeyA 我不确定这是否重要,但我稍微编辑了一下......基本上在定制逻辑中处理每一行
  • @Botje 我不确定。没有公认的答案,评价很高的答案基本上是说要按照我的要求做,但不是如何做。所以我不认为这是一个骗局

标签: c++ file


【解决方案1】:

在逐行读取不断增长的文件时需要注意几个问题:

  1. 生产者可能不需要以原子方式将行写入文件。 std::getline/gets 去掉尾随的\n,所以你不知道它是读了整行还是EOF 被击中了。
  2. C++ 标准库中没有等待文件增长的工具。

您需要编写自己的getline

  1. 读入一个固定长度的缓冲区,该缓冲区必须至少与生产者可以写入的最长行一样大。使用特定于平台的函数,例如 POSIX read,这样您就不需要在 ifstreamFILE* 上不断清除 EOF 状态。
  2. 在缓冲区中找到完整的行并将它们传递给调用者。不完整的行被移到缓冲区的开头,随后的read 读取该不完整的行。
  3. EOFread 匹配时,使用特定于平台的方式(如inotify)等待文件增长。如果没有竞争条件,这可能很难实现,因此您可能希望在合理的超时后重试读取文件。转到 1。

【讨论】:

  • 在问题 2 上,是的,如果返回 EOF,我认为计时器是合适的。就此而言,我很乐意等到整行 \n 终止,除非我只是继续阅读尽可能多的字节并自行检查换行符?
  • @Mr.Boy 是的,你继续阅读尽可能多的内容并继续扫描缓冲区中的\n
  • 但是就我的查询而言,我不需要担心整个文件会被加载到内存中——标准库会以一种有效的方式处理文件搜索?
  • @Mr.Boy 标准库永远不会将整个文件读入内存,除非它小于读取缓冲区。使用 POSIX read 您只能绕过标准库缓冲区读取缓冲区大小。
猜你喜欢
  • 2013-09-27
  • 2013-01-22
  • 2012-07-30
  • 1970-01-01
  • 2012-08-30
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 2018-07-11
相关资源
最近更新 更多