一旦write 或writev 返回(即操作系统已接受),操作系统负责将数据写入磁盘。这不再是您的问题,并且无论您的进程是否崩溃,它都会发生。请注意,您无法控制一次接受或实际写入的数据量,也无法控制它是否发生在多个文件系统块中,或者它是否具有任何特定大小。您向write 发送请求,它会告诉您它实际接受了多少,它会自行决定将其写入磁盘。
这可能会以块大小的倍数发生,因为操作系统这样做是有意义的,但不能以任何方式保证(在许多系统上,包括 Linux,读取和写入是通过或与文件映射紧密耦合)。
同样的“不必关心”保证适用于文件映射(理论上的例外是,崩溃的应用程序原则上仍然可以写入仍然映射的区域,但是一旦您取消映射区域,就不会发生这种情况甚至理论上)。除非您拔掉插头(或内核崩溃),否则数据将被写入,并且是一致的。
数据只会被写入文件系统块的倍数,因为内存页面是设备块的倍数,而文件映射不知道其他任何东西,它就是这样工作的。
您可以某种(忽略任何可能的无缓冲磁盘写入缓存)使用fdatasync 对磁盘上的内容进行一些控制。当该函数返回时,之前缓冲区中的内容已被发送到磁盘。
但是,这仍然不能阻止您的进程同时在另一个线程中崩溃,也不能阻止有人拔掉插头。 fdatasync 比 fsync 更可取,因为它不会触及 inode 附近的任何东西,这意味着它更快更安全(您可能会丢失在后续崩溃中写入的最后数据,因为长度尚未更新,但您永远不应该销毁/损坏整个文件)。
C 库函数 (fwrite) 进行自己的缓冲并让您控制写入的数据量,但“写入”数据仅意味着它存储在 C 库拥有的缓冲区中(在您的进程中) )。如果进程死了,数据就消失了。无法控制数据如何到达磁盘,或者如果有的话。 (注意:您确实有一些控制权fflush,这将在返回之前立即将缓冲区的内容传递给底层的写入函数,很可能是writev。这样,你又回到了第一段。)
异步 IO (kernel aio) 将绕过内核缓冲区,通常直接从您的进程中提取数据。你的进程死了,你的数据消失了。 Glibc aio 使用在write 上阻塞的线程,适用于第 1 段。
如果您随时拔掉插头或按下“关闭”开关会怎样?没有人知道。
通常会丢失一些数据,一个操作系统可以提供很多保证,但它不能发挥神奇的作用。尽管从理论上讲,您可能有一个用电池缓冲 RAM 的系统,或者一个具有巨大的专用磁盘高速缓存的系统,该高速缓存也由电池供电。谁也说不清。无论如何,请为丢失数据做好准备。
也就是说,如果您继续附加到文件,曾经写入的内容通常不应该被破坏(虽然,真的任何事情都可能发生,“不应该”并不意味着很多)。
总而言之,在追加模式下使用write 或文件映射应该已经足够好了,无论如何它们都已经足够好了。除了突然断电之外,它们还可靠且高效。
如果电源故障是一个问题,UPS 将提供比任何软件解决方案更好的保证。
至于文件大小,我认为没有任何理由人为地限制文件大小(假设一个相当新的文件系统)。 “标准”Linux 文件系统(如果有的话)的通常文件大小限制在 TB 范围内。
无论哪种方式,如果您对因任何原因损坏一个文件可能会破坏 30 天的数据的想法感到不安,请每天创建一个新文件。无需额外费用。