在我的嵌入式系统上,我想确保在关闭文件时安全地写入数据 - 如果系统报告数据已保存,则用户应该能够立即断电。
我知道执行此操作的正确方法是目录上的fsync()
,fclose()
和fsync()
(cfr。this blog entry)。但是,在我的情况下获取目录的文件描述符有点棘手(我必须通过/proc/self/fd
找回文件名并从那里派生目录)。在整个文件系统上执行syncfs()
对我来说会简单得多 - 我知道这是文件系统上唯一打开的文件。
现在我的问题是:
syncfs()
是否足够?fclose()
FILE *
(目录条目是最新的)?或fflush()
是否足够?dup()
文件描述符是否有用,以便我可以直接将其用于syncfs()
?答案 0 :(得分:1)
在文件系统(/ etc / fstab)中启用“sync”标志,默认为“async”(禁用)。启用此标志后,对相应文件系统的所有更改都将立即刷新到磁盘。这会使整个文件系统变慢,但根据您的嵌入式系统要求,这可能是一个很好的选择。
答案 1 :(得分:1)
首先,不要将标准库<stdio.h>
调用(例如fprintf(3)
或fopen(3)
)与系统调用混合(例如open(2)
或{{1} }或close(2)
)因为前者是使用进程中的库例程。缓冲区用于存储系统不知道的临时数据,其他缓冲区是操作系统接口,使系统从现在开始负责数据维护。您可以轻松区分它们,因为前者使用sync(2)
描述符进行操作,而最后一次使用FILE *
整数描述符进行操作。
因此,如果您使用系统调用来确保您的数据已正确同步到磁盘,首先必须int
您的流程&#39;在执行文件系统fflush(3)
或sync(2)
调用之前缓冲数据。
不保证fsync(2)
sync(2)
或fclose(3)
时间,或close(2)
之前atexit()
回调过程中exit()
。{br> />
出于性能原因,操作系统缓冲区被写入延迟,而close(2)
不是使其触发此类事件的事件。只是认为许多进程可以同时读取和写入同一个文件,并且每个触发文件系统刷新的close(2)
都可能很难实现。操作系统会定期,umount(2)
系统调用,系统关闭以及对sync(2)
和fsync(2)
系统调用的特定调用触发此类调用。
如果您需要维护FILE *fd
描述符,只需为该描述符执行fflush(fd)
以确保操作系统具有fwrite(3)
d或{{1}的所有缓冲区首先是数据。
最后,如果您使用fprintf(3)
函数,请首先为您写入的所有<stdio.h>
描述符执行fflush()
,或致电FILE *
告诉stdio在一次通话中同步所有描述符。然后执行fflush(NULL);
或sync(2)
调用以确保您的所有数据都在磁盘上。无需关闭任何东西。
fsync(2)
顺便说一句,你前往FILE *fd;
...
fflush(fd);
fsync(fileno(fd));
/* here you know that up to the last write(2) or fwrite(3)...
* data is synced to disk */
获取描述符(你之前有过)的方法有两个原因:
关闭描述符后,/dev/fd/<number>
不再是您想要的描述符。通常情况下,它甚至不存在。试试这个:
/dev/fd/<number>
只能使用文件描述符来获取打开文件所属的目录。在多链接文件中,可能有数千个目录只指向它。 inode(或打开的文件结构)中没有任何内容可以让您获取用于打开该文件的路径。使用临时文件的常用方法是创建它们并立即#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main()
{
int fd;
char fn[] = "/dev/fd/1";
close(1); /* close standard output */
fd = open(fn, O_RDONLY); /* try to reopen from /dev/fd */
if (fd < 0) {
fprintf(stderr,
"%s: %s(errno=%d)\n",
fn,
strerror(errno),
errno);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} /* main */
它们,因此没有人可以再次打开它。尽管您保留文件打开,但您可以访问它,但是没有路径指向它。