应该在每次fclose之后使用fsync吗?

时间:2017-05-05 10:34:09

标签: c linux file stdio

在Linux(Ubuntu平台)设备上,我使用文件来保存关键任务数据。

有时(大约10,000个案例中一次),文件因未指明的原因而被破坏。 特别是,文件被截断(而不是一些kbyte,它只有大约100个字节)。

现在,按照软件的顺序

  1. 文件已打开,
  2. 已修改
  3. 关闭。
  4. 在此之后,文件可能会再次打开(4),还有其他事情正在完成。

    到目前为止,我没有注意到,fflush(调用fclose)不会写入文件系统,而只会写入中间缓冲区。可能是,3)和4)之间的时间太短而且2)的变化尚未写入光盘,所以当我重新打开4)时,我得到一个截断的文件,当它再次关闭时会导致永久丢失这些数据?

    在每个文件写入后,我应该在这种情况下使用fsync()吗?

    停电时我需要考虑什么?数据损坏与断电有关并非不可能。

3 个答案:

答案 0 :(得分:3)

fwrite首先写入内部缓冲区,然后有时(在fflushfclose或缓冲区已满时)调用OS函数write

操作系统也在做一些缓冲,对设备的写入可能会延迟。

fsync确保操作系统正在将缓冲区写入设备。

如果你打开 - 写 - 关闭,你不需要fsync。操作系统知道文件的哪些部分尚未写入设备。因此,如果第二个进程想要读取该文件,则OS知道它在内存中具有文件内容,并且不会从设备读取文件内容。

当然,在考虑停电时,可能(视情况而定)对fsync来说是个好主意,以确保将文件内容写入设备(正如Andrew指出的那样,不一定意味着内容被写入光盘,因为设备本身可能会进行缓冲)。

答案 1 :(得分:2)

  

到目前为止,我没有注意到,fflush(在fclose上调用)不会写入文件系统,而只会写入中间缓冲区。可能是,3)和4)之间的时间太短而且2)的变化尚未写入光盘,所以当我重新打开4)时,我得到一个截断的文件,当它再次关闭时会导致永久丢失这些数据?

没有。以这种方式行事的系统将无法使用。

  

在每个文件写入后,我应该在这种情况下使用fsync()吗?

不,这只会减慢速度。

  

对于停电,我需要考虑什么?与数据损坏无关,这与断电有关。

使用能够抵御此类损坏的文件系统。甚至可能考虑使用更安全的修改算法,例如使用不同的名称写出新版本的文件,同步,然后在现有文件的顶部重命名。

答案 2 :(得分:1)

如果您正在做的事情是这样的话:

FILE *f = fopen("filename", "w");
while(...) {
    fwrite(data, n, m, f);
}
fclose(f);

然后可能发生的另一个进程可以在写入文件时打开文件(在C库在后台运行的openwrite系统调用之间,或者在单独的{{1调用)。然后他们只会看到一个部分写入的文件。

解决方法是使用其他名称编写文件,并在实际文件名上write。缺点是你需要两倍的空间。

如果您确定在写入后仅发生文件打开,那么就不会发生这种情况。但是必须在作者和读者之间进行一些同步,以便后者不会过早开始阅读。

rename()告诉系统将更改写入实际存储,这在其他POSIX系统调用中有点奇怪,因为我认为如果系统崩溃没有指定任何系统,那就是只有当某些数据存储在实际存储中而不存储在某些缓存中时才重要的情况。即使使用fsync(),存储硬件仍然可以缓存数据,或者当系统崩溃时,不相关的损坏仍然可以废弃文件系统。

如果您乐意让操作系统完成其工作,并且不需要考虑崩溃,您可以完全忽略fsync()并在操作系统认为合适时让数据写入。如果您关心崩溃,您必须更仔细地查看文件系统保证(或不保证)的内容。例如。至少在某些时候,fsync()开发人员几乎要求应用程序在包含目录上执行ext*