【问题标题】:Difference between fflush and fsyncfflush 和 fsync 的区别
【发布时间】:2011-01-21 09:18:39
【问题描述】:

我认为fsync() 在内部执行fflush(),所以在流上使用fsync() 是可以的。但是在网络 I/O 下执行时,我得到了一个意想不到的结果。

我的代码sn-p:

FILE* fp = fopen(file, "wb");
/* multiple fputs() calls like: */
fputs(buf, fp);
...
...
fputs(buf.c_str(), fp);
/* get fd of the FILE pointer */
fd = fileno(fp);
#ifndef WIN32
ret = fsync(fd);
#else
ret = _commit(fd);
fclose(fp);

但似乎_commit() 没有刷新数据(我在 Windows 上尝试过,数据是在 Linux 导出的文件系统上写入的)。

当我将代码更改为:

FILE* fp = fopen(file, "wb");
/* multiple fputs() calls like: */
fputs(buf, fp);   
...   
...
fputs(buf.c_str(), fp);
/* fflush the data */
fflush(fp);
fclose(fp);

它刷新数据。

我想知道_commit() 是否与fflush() 做同样的事情。有输入吗?

【问题讨论】:

  • 您在第一个示例中看到的问题是什么?
  • @rogerdpack 在第一个示例中,即使在 fd(文件描述符)上调用 _commit() 函数,通过 fputs() 写入流也不会同步/提交到磁盘。该测试是在集群系统下完成的,其中远程 linux 文件系统导出为 CIFS 并在 Windows 机器上使用,并且在写入期间测试节点故障转移。当节点恢复时,发现文件大小为零。
  • #endif在哪里?
  • 该问题在内部是一致的,并且在修订 #5 之前的答案也与之一致,这从根本上改变了问题的性质。回滚到修订版 #4。

标签: fflush fsync c windows


【解决方案1】:

fflush() 适用于FILE*,它只是将应用程序的FILE* 中的内部缓冲区刷新到操作系统。

fsync 在较低级别上工作,它告诉操作系统将其缓冲区刷新到物理介质。

操作系统会大量缓存您写入文件的数据。如果操作系统强制每次写入都命中驱动器,那么事情会非常慢。 fsync(除其他外)允许您控制数据何时应该到达驱动器。

此外,fsync/commit 作用于文件描述符。它不知道FILE*,也无法刷新其缓冲区。 FILE* 存在于您的应用程序中,文件描述符通常存在于操作系统内核中。

【讨论】:

  • 谢谢我在同一条线上思考。所以如果我们使用 FILE* 那么同样可以通过 fflush() 后跟 fsync() 来实现。
  • 不,因为你不能 fsyncFILE*
  • @patrickvacek 实际上,您可以使用来自stdio.hint fileno(FILE * stream);FILE * 获取文件描述符。
  • @jotik:您应该使用 either(标准)FILE * 函数,(操作系统)文件句柄。你不要混合它们。而fileno() 不是标准函数。不幸的是,众所周知,人们对“扩展”标准标题的松懈...
  • @DevSolar - fileno() 是 POSIX 标准的一部分,因此虽然它不一定是可移植的,但它在某些平台上是标准的。
【解决方案2】:

标准 C 函数 fflush() 和 POSIX 系统调用 fsync() 在概念上有些相似。 fflush() 对 C 文件流(FILE 对象)进行操作,因此是可移植的。 fsync() 对 POSIX 文件描述符进行操作。 两者都会导致缓冲数据被发送到目的地。

在 POSIX 系统上,每个 C 文件流 has an associated file descriptor,以及对 C 文件流的所有操作都将在必要时通过委托对文件描述符进行操作的 POSIX 系统调用来实现。

有人可能会认为在 POSIX 系统上调用 fflush 会导致文件流缓冲区中的任何数据的 write,然后调用 fsync() 以获取该文件流的文件描述符.因此,在 POSIX 系统上,无需在调用fflush 之后再调用fsync(fileno(fp))。但情况是否如此:fflush 是否有对fsync 的呼叫?

不,在 POSIX 系统上调用 fflush 并不意味着将调用 fsync

fflush 的 C 标准说(强调)它

导致 [the] 流的任何未写入数据被传递到主机环境被写入到文件中

说数据要写入,而不是正在写入意味着允许主机环境进一步缓冲。对于 POSIX 环境,“主机环境”的缓冲可能包括 fsync 刷新的内部缓冲。因此,仔细阅读 C 标准表明该标准不需要 POSIX 实现调用fsync

POSIX standard description of fflush 不声明,作为 extension of the C semanticsfsync 被调用。

【讨论】:

    【解决方案3】:

    为了简单起见,我可以这么说:

    fsync() 与非流式文件(整数文件描述符)一起使用

    fflush() 用于文件流。

    这里还有人的帮助:

    int fflush(FILE *stream); // flush a stream, FILE* type
    
    int fsync(int fd); // synchronize a file's in-core state with storage device
                        // int type
    

    【讨论】:

    • 那么fflush() 会为你隐式调用fsync() 吗?
    • @binki no - 它在缓冲数据上调用write()
    • 啊,看起来问题被编辑为问错了问题,在我查看后已修复(当我查看时,问题是“fflush() 是否调用 fsync()你?,现在又回到了荒谬的“fsync() 是否会为你调用fflush(),这是不可能的,因为你可以将FILE* 映射到fd,但不能将fd 映射到FILE*)。所以@Guillaume,你是说你需要做fflush()然后 fsync()除非你要fclose()这无论如何都会为你做这件事,哦,fclose() 不会自动刷新,xD)。
    • @binki 如果您想确保所有写入的数据(由缓冲和非缓冲 I/O 写入)都在支持文件的物理介质上。您需要同时致电fflush()fsync(),是的。一般来说,关心这一点的人不会使用缓冲 I/O(例如使用 setvbuf()),所以他们通常只使用 fsync()
    【解决方案4】:

    fflush()fsync() 可用于尝试确保将数据写入存储介质(但并非总是可行):

    1. 首先在输出流上使用fflush(fp)fp 是从fopen 或标准流之一stdoutstderr 获得的FILE *)写入与流式传输到操作系统。
    2. 然后使用fsync(fileno(fp)) 告诉操作系统将自己的缓冲区写入存储介质。

    但是请注意,fileno()fsync() 是 POSIX 函数,可能并非在所有系统上都可用,尤其是在 Microsoft 旧系统中,替代品可能被命名为 _fileno()_fsync()_commit()...

    【讨论】:

    • 这是解释需要调用fflushfsync 的完整过程的唯一答案,所以我最喜欢这个答案。
    【解决方案5】:

    要强制将最近的更改提交到磁盘,请使用 sync() 或 fsync() 函数。

    fsync() 会将所有给定文件的数据和元数据与永久存储设备同步。应该在相应文件关闭之前调用它。

    sync() 会将所有修改过的文件提交到磁盘。

    【讨论】:

    • 我们正在讨论 b/w fsync 与 fflush 的区别
    【解决方案6】:

    我认为下面来自 python (https://docs.python.org/2/library/os.html) 的文档很好地阐明了这一点。

    os.fsync(fd) 强制将带有文件描述符 fd 的文件写入磁盘。在 Unix,这调用了本机 fsync() 函数;在 Windows 上,MS _commit() 函数。

    如果你从 Python 文件对象 f 开始,首先执行 f.flush(), 然后执行 os.fsync(f.fileno()),以确保所有内部缓冲区 与 f 关联的内容被写入磁盘。

    可用性:从 2.2.3 开始的 Unix 和 Windows。

    【讨论】:

      猜你喜欢
      • 2015-07-23
      • 2015-08-20
      • 2023-03-07
      • 2016-09-28
      • 2021-04-25
      • 2017-05-13
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      相关资源
      最近更新 更多