1

我正在 Linux 环境中开发 C 代码。我fwrite用来将一些数据写入一些文件。该程序将在经常发生断电(至少一天一次)的环境中运行。因此,我想fwrite确保如果在写入数据时发生断电,文件不应该被更新。它应该只在fwrite完成其工作时保存文件。fwrite只有完成写入过程,我才能使用它来影响文件?

编辑:我使用 fopenwb来丢弃文件中的先前信息并编写一个新文件,例如

FILE *rtng_p;
rtng_p = fopen("/etc/routing_table", "wb");
fwrite(&user_list, sizeof(struct routing), 40, rtng_p);

它是一个非常小的数据,一些字节长

4

3 回答 3

6

首先将文件写入同一文件系统上的临时路径,例如/etc/routing_table.tmp. 然后只需在原始文件顶部重命名副本即可。重命名保证是原子的。

所以,调用的顺序是, fopen, fwrite, fclose, rename

于 2013-06-25T18:22:44.443 回答
2

除了David Schwartz 回答中给出的序列之外,您也许可以将咨询锁与例如flock(2)系统调用一起使用(或者也许lockf(3)fcntl(2)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); };

使用这种咨询锁定将确保即使您的程序的两个进程正在运行,也只有一个进程会写入文件。

但这可能是矫枉过正。

顺便说一句,您似乎在/etc/. 我相信这违反了习惯或约定(请参阅Linux Filesystem HierarchyLinux Standard Base)。我希望下面/etc的文件是文本的。也许您希望您的文件在/var/lib?

另请参阅在线高级 Linux 编程书籍。

于 2013-06-25T19:33:49.477 回答
1

在 UNIX/Linux 社区中,关于open/write/close/rename模式(如David Schwartz 的回答中所描述的)是否真的保证是原子的存在很大的争论。请注意,此对话是关于write而不是fwrite

EXT4 文件系统的主要作者不认为它应该根据 POSIX 得到保证,并且文件系统的早期版本并不将其视为原子的。最终,他投降了,并将这组操作设为原子操作作为 EXT4 的默认行为。然而,有人声称用户程序实际上应该在做open/write/fsync/close/rename.

fsync其他文件系统可能不保证没有noauto_da_alloc. 因此,如果您想真正安全,则应fsync在. 我还没有尝试过,如果你使用它可能会起作用。closerenamefwritefflush

有关更多信息,请参阅https://www.kernel.org/doc/Documentation/filesystems/ext4.txtauto_da_alloc部分。另请参阅此处 EXT4 的主要作者撰写的文章:http: //thunk.org/tytso/blog/2009/03/12/delayed-allocation-and-the-zero-length-file-problem/

于 2016-04-19T19:21:43.047 回答