每次fclose后是否应使用fsync?

每次fclose后是否应使用fsync?,c,linux,file,stdio,C,Linux,File,Stdio,在Linux(Ubuntu平台)设备上,我使用一个文件来保存关键任务数据 有时(大约10000个案例中有一次),文件会因未指明的原因而损坏。 特别是,文件被截断(它只有大约100个字节,而不是一些KB) 现在,按照软件的顺序 文件打开后 修改和 关闭 紧接着,该文件可能会再次打开(4),并执行其他操作 到目前为止,我没有注意到,fflush(称为fclose)不写入文件系统,而只写入中间缓冲区。是不是3)到4)之间的时间太短,2)的更改还没有写入光盘,所以当我用4)重新打开时,会得到一个被截断的

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

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

现在,按照软件的顺序

  • 文件打开后
  • 修改和
  • 关闭
  • 紧接着,该文件可能会再次打开(4),并执行其他操作

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

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


    对于停电,我该考虑什么?数据损坏不太可能与断电有关。

    fwrite
    首先写入内部缓冲区,然后有时(在
    fflush
    fclose
    或缓冲区已满时)调用操作系统函数
    write

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

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

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

    当然,在考虑断电时,(根据具体情况)最好
    fsync
    确保文件内容被写入设备(正如安德鲁指出的,这并不一定意味着内容被写入光盘,因为设备本身可能会进行缓冲)

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

    不,这样的系统将无法使用

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

    不,那只会让事情变慢

    我该如何考虑权力外逃?数据损坏很可能与断电有关


    使用能够抵抗这种破坏的文件系统。甚至可以考虑使用一个更安全的修改算法,例如用不同的名称编写一个新版本的文件,同步,然后在现有文件的顶部重命名它。

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

    FILE *f = fopen("filename", "w");
    while(...) {
        fwrite(data, n, m, f);
    }
    fclose(f);
    
    然后,可能发生的情况是,另一个进程可以在写入文件时打开该文件(在C库在后台运行的
    open
    write
    系统调用之间,或者在单独的
    write
    调用之间)。然后,他们将只看到部分写入的文件

    解决方法是使用另一个名称写入文件,然后
    rename()。缺点是需要两倍的空间

    如果您确定仅在写入之后才打开文件,则无法打开。但是,作者和读者之间必须有一些同步,这样读者才不会过早开始阅读

    fsync()
    告诉系统将更改写入实际存储,这在其他POSIX系统调用中有点奇怪,因为我认为如果系统崩溃,则不会指定系统的任何内容,这是唯一一种情况,如果某些数据存储在实际存储上,而不是存储在某个缓存中,这才是重要的。即使使用
    fsync()
    ,存储硬件仍有可能缓存数据,或者在系统崩溃时,不相关的损坏也有可能将文件系统丢弃


    如果您愿意让操作系统完成它的工作,并且不需要考虑崩溃,那么您可以完全忽略
    fsync()
    ,在操作系统认为合适的时候写入数据。如果您确实关心崩溃,那么您必须更仔细地研究文件系统提供(或不提供)哪些保证。例如,
    ext*
    开发人员至少在某一点上要求应用程序在包含目录上执行
    fsync()

    您不能打开、修改、写入临时文件、关闭、刷新、删除原始文件(或移动到备份文件夹)、重命名吗?此外,请确保您正在检查
    fclose()
    中的返回值。因为它隐式地调用
    fflush()
    来写入数据,所以它可能会失败,就像任何写入数据的stdio调用一样。“更安全的修改算法”-是的,这正是我要做的。
    fsync
    以确保文件内容被写入光盘。但这仅仅意味着磁盘设备(无论是RAID控制器还是实际磁盘)已经接受了数据。这并不意味着数据是安全存储的——磁盘设备也在内存中缓存数据。fflush是c流库的一部分。他使用的是fopen fclose,而不是open-close。@罗伯特雅各布斯,这没关系,最晚在关闭文件时,C库必须在某个时候调用
    write()
    。无论如何,编辑以显示stdio调用。