我正在Linux环境中开发C代码。我使用fwrite
将一些数据写入某些文件。该计划将在经常断电(至少每天一次)的环境中运行。因此,我希望fwrite
确保在写入数据时发生断电时不应更新该文件。它应该只在fwrite
完成其工作时保存文件。如何使用影响文件的fwrite
只有完成写入过程?
编辑:我使用fopen和wb
来丢弃文件中的先前信息并写一个新文件,例如
FILE *rtng_p;
rtng_p = fopen("/etc/routing_table", "wb");
fwrite(&user_list, sizeof(struct routing), 40, rtng_p);
并且它是一些非常小的数据,长度为
答案 0 :(得分:6)
首先将文件写入同一文件系统上的临时路径,如/etc/routing_table.tmp
。然后只需将副本重命名为原始文件。重命名是保证原子的。
因此,调用顺序为fopen
,fwrite
,fclose
,rename
。
答案 1 :(得分:2)
除了David Schwartz answer中给出的序列之外,您可以使用咨询锁定,例如flock(2)系统调用(或lockf(3) fcntl(2) Linux Filesystem Hierarchy F_SETLK
....)
这意味着在
之后添加 FILE * fil = fopen("/etc/routing_table.tmp", "wb");
行
if (!fil)
{ perror("/etc/routing_table.tmp"); exit(EXIT_FAILURE); };
if (flock(fileno(fil), LOCK_EX))
{ perror("flock LOCK_EX"); exit(EXIT_FAILURE); };
最后,你会
if (fflush(fil)) /* flush the file before unlocking it!!*/
{ perror("fflush"); exit(EXIT_FAILURE); };
if (flock(fileno(fil), LOCK_UN))
{ perror("flock LOCK_UN"); exit(EXIT_FAILURE); };
if (fclose (fil))
{ perror("fclose"); exit(EXIT_FAILURE); };;
if (rename("/etc/routing_table.tmp", "/etc/routing_table"))
{ perror("rename"); exit(EXIT_FAILURE); };
使用这种建议锁定可以确保即使程序的两个进程正在运行,也只有一个程序会写入该文件。
但可能是过度杀伤。
BTW,您似乎在/etc/
中编写二进制数据。我认为这违反了习惯或惯例(见Linux Standard Base或Advanced Linux Programming)。我希望/etc
下的文件是文本的。也许您希望自己的文件位于/var/lib
?
另见{{3}}在线预订。
答案 2 :(得分:1)
在UNIX / Linux社区中有一个很大的争论,即open/write/close/rename
模式(如David Schwartz's answer中所述)是否确实是原子的。请注意,此对话是关于write
而不是fwrite
!
EXT4文件系统的主要作者不相信它应该根据POSIX保证,并且早期版本的文件系统不会将其视为原子。最终他投降并使这组操作成为EXT4的默认行为。但是,声称用户程序实际上应该执行open/write/fsync/close/rename
。
如果没有fsync
,其他文件系统可能无法保证原子性,如果EXT4与noauto_da_alloc
一起安装,那么该保证也会丢失。因此,如果您想要非常安全,则应在fsync
close
之后添加rename
。我没有尝试使用fwrite
,如果您使用fflush
可能会有效。
有关详情,请参阅https://www.kernel.org/doc/Documentation/filesystems/ext4.txt的auto_da_alloc
部分。另请参阅EXT4主要作者撰写的文章:http://thunk.org/tytso/blog/2009/03/12/delayed-allocation-and-the-zero-length-file-problem/