【问题标题】:Reading file that changes over time C++读取随时间变化的文件 C++
【发布时间】:2013-07-05 16:39:22
【问题描述】:

我打算用 C++ 读取一个文件。读取本身发生在一个while循环中,并且正在从一个文件中读取。

当函数从文件中读取信息时,它会将这些信息推送到系统中的某个位置。问题是这个文件可能会在循环进行时发生变化。

我怎样才能在文件中捕捉到这些新信息?我尝试std::ifstream 在我的计算机上手动读取和更改我的文件,因为无限循环(每个循环之间有一个sleep(2))正在进行,但正如预期的那样 - 没有发生任何事情。

编辑:文件将在每次向文件中输入新数据时覆盖自身。

帮助?

在虚拟机 Ubuntu Linux 12.04 上运行,如果这可能是有用的信息。这不是家庭作业。

【问题讨论】:

    标签: c++ file input output


    【解决方案1】:

    通常的解决方案类似于 MichaelH 建议:写入过程以追加模式打开文件,并且 总是写到最后。阅读过程做了什么 MichaelH 建议。

    这适用于每次运行中的少量数据。如果 进程应该运行很长时间,并产生大量 数据,文件最终会变得太大,因为它会 还包含所有已处理的数据。在这种情况下, 解决方案是使用一个目录,在其中生成编号文件, 每个数据记录一个文件。编写过程将编写每个 数据集到一个新文件(增加数字),和 读取过程将尝试打开新文件,并将其删除 当它完成时。这比 第一个建议,但甚至适用于流程 每秒生成大量数据并运行 年。

    编辑:

    后来 OP 的 cmets 说该设备实际上是一个 FIFO。 在这种情况下:

    • 你不能寻求,所以不能使用 MichaelH 的建议 从字面上看,但是

    • 您无需查找,因为数据会自动删除 每当它被读取时从 FIFO 中读取,并且

    • 根据数据的大小和写入方式, 写入可能是原子的,所以你不必担心部分 记录,即使您恰好在中间阅读 写。

    关于后者:确保读取和 写缓冲区足够大以包含完整的记录,并且 作家在每条记录后刷新。并确保 记录小于保证所需的大小 原子性。 (从历史上看,在我所知道的早期 Unix 上,这是 4096,但如果从那以后它没有增加,我会感到惊讶 然后。虽然......在Posix下,这是由PIPE_BUF定义的, 只保证至少512,只有4096 在现代 Linux 下。)

    【讨论】:

    • I/O 负载系统仍有可能丢失数据。在读取进程读取、处理部分文件并删除它之前,写入进程可能尚未完成写入。
    • @suspectus 如果这是一个问题,您可以写入一个临时文件,然后在关闭后重命名它。通常,在这种情况下,我会写一个校验和。读取时,如果校验和不正确,我不处理文件。
    【解决方案2】:

    只需读取文件,重命名文件,打开重命名的文件。对系统进行数据处理,并在循环结束时关闭文件。睡眠后,重新打开白色循环顶部的文件,重命名并重复。

    这是解决问题的最简单方法,并且不必在处理阶段编写代码来处理文件的动态更改。

    为确保您没有损坏,最好重命名文件。这保证了来自另一个进程的任何更改都不会影响处理。可能没有必要这样做 - 这取决于处理和文件的更新方式。但这是一种更安全的方法。移动或重命名操作保证是原子的 - 所以如果使用这种方法应该不会有并发问题。

    【讨论】:

    • 如果在我睡觉的时候文件上有一个新的输入,当我重新打开时又有一个新的输入,我不会错过数据吗?
    • 重新打开文件就会发现
    • 即使文件上的数据每次都覆盖自己?无论如何,我现在要使用这个解决方案。如果我的其他队友对此抱怨,宁愿接受批评。感谢您的回复:)
    • 我已经修改了我的答案 - 我认为最安全的方法是重命名文件(如果可能)然后处理重命名的文件。这种问题可能会间歇性地困扰您,并且可能需要花费时间和精力来解决。
    • 如果数据源每次重新打开文件并在开始时写入数据,并且在您醒来之间写入两次,您将丢失数据。
    【解决方案3】:

    您可以使用inotify 来查看文件更改。 如果您需要更简单的解决方案 - 读取文件属性(使用 stat(),并检查文件的 last_write_time)。

    但是,在打开和重新读取文件时,您仍然可能会错过一些文件修改。因此,如果您可以控制写入文件的应用程序,我建议您使用其他方式在这些进程之间进行通信,例如管道。

    【讨论】:

    • 嗯,这不是一个文件,而是一个内核模块写入的设备。我只是应该把它当作一个文件。
    • @matkapluku 什么样的设备。设备的行为与文件完全不同。例如,对于 fifo 之类的东西,您应该保持文件打开(在两端),因为您无法搜索。读取会删除数据,因此您不必担心磁盘已满,即使写入器连续数年追加。
    • @JamesKanze:是的,我们将使用 fifo。
    • @matkapluku 在这种情况下,作者几乎肯定不会覆盖,但会附加信息。 (而且如果每次写入的大小足够小,系统会保证它是原子的,这样读者就不用担心部分记录了。)
    • 好的。我认为我们正在以我将调用位于内核模块中的函数read 的方式解决它(不太确定我的队友 - 正在编写驱动程序 - 正在计划 atm)。我将从该函数收到char[]。时间会证明一切。当我走到那一步时,我会用我的解决方案更新这个 Q。
    【解决方案4】:

    更明确地说,如果你想要类似尾巴的行为,你会想要:

    1. 打开文件,读入数据。保存长度。关闭文件。
    2. 稍等。
    3. 再次打开文件,尝试寻找到最后读取的位置,读取剩余数据,关闭。
    4. 冲洗并重复

    【讨论】:

    • 这假设写入过程保持文件打开,或者它做了类似的事情。如果进程的生命周期很长,那么您很容易以磁盘已满而告终。
    • 是什么让你认为写作过程做了类似的事情?它可以随意关闭和打开文件,只要它在写入文件时不要求同时进行独占读写访问。
    • 因为如果写入过程关闭,然后重新打开同一个文件(覆盖数据),它将不起作用。该算法(这是处理问题的或多或少的标准方法)假设写入过程始终将数据附加到文件中,并且从不覆盖。如果进程是“短暂的”(在这种情况下,“短暂”可能意味着一两天,具体取决于写入的内容),并且编写器在打开时总是打开截断,这可能是一个非常好的解决方案。如果进程运行了几年,而写入器每秒写入 1 MB,则不是。
    • 啊。海报改变了条件。他最初并没有说新数据将覆盖原始数据。正如最初所说,他暗示将附加数据。
    • 是的。我不知道他是否暗示过,但他没有说任何与它相矛盾的话,而且这种情况比较常见。
    猜你喜欢
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 2018-03-14
    • 2017-11-20
    • 1970-01-01
    相关资源
    最近更新 更多