背景:在vm虚拟机上,通过ofstream创建文件,机器重启后偶发内容消失。
1) 原版代码
代码
std::ofstream fout("test.txt");
fout << "test";
fout.close();
2)问题解释
fopen 写入文件不一定写入磁盘_commit()
在C语言中,使用fopen
函数打开文件进行写入时,数据通常会被写入到操作系统提供的文件系统缓存中,而不是直接写入到磁盘上。这种机制可以提高程序的性能,因为它允许程序在多个写操作之间累积数据,然后在合适的时候(例如,程序结束、调用fflush
函数或操作系统决定将缓存内容写入磁盘时)将数据写入磁盘。
如果你需要确保数据已经被写入磁盘,而不是仅仅停留在操作系统的缓存中,你可以采取以下几种方法:
1. 使用fflush
函数
fflush
函数可以用来刷新输出或更新文件流。当你调用fflush
时,它会将所有未写的数据从文件流缓冲区传输到文件中。对于输出文件流,这会导致数据被写入磁盘。
#include <stdio.h>
FILE *fp = fopen("example.txt", "w");
if (fp != NULL) {
fputs("Hello, world!", fp);
fflush(fp); // 确保数据被写入磁盘
fclose(fp);
}
2. 使用fsync
函数
如果你正在使用POSIX兼容的操作系统(如Linux或UNIX),你可以使用fsync
函数来同步一个文件的描述符。这确保了所有对该文件描述符的写操作都已从内核缓冲区传输到磁盘。
#include <unistd.h>
#include <fcntl.h>
int fd = open("example.txt", O_WRONLY);
if (fd != -1) {
write(fd, "Hello, world!", 13);
fsync(fd); // 确保数据被写入磁盘
close(fd);
}
3. 程序终止时自动刷新和同步
在某些情况下,当程序正常终止时(例如,通过exit
函数),操作系统会自动刷新并同步所有打开文件的缓冲区。然而,这不是一个可靠的方法来确保在程序执行期间的数据完整性,特别是在需要即时数据持久化的场景中。
4. 使用_commit
函数(特定于Windows)
在Windows平台上,可以使用_commit
函数来提交文件流的缓冲区到磁盘。这对于需要确保数据立即写入磁盘的应用程序非常有用。
#include <io.h>
#include <fcntl.h>
int fd = _open("example.txt", _O_WRONLY);
if (fd != -1) {
_write(fd, "Hello, world!", 13);
_commit(fd); // 确保数据被写入磁盘
_close(fd);
}
结论
根据你的具体需求和运行环境(如跨平台或特定于Windows),你可以选择合适的方法来确保数据写入磁盘。在大多数情况下,使用fflush
或fsync
(在POSIX系统上)是足够好的选择。对于Windows平台,使用_commit
可以提供额外的控制。
3) 解决
目前下述代码通过测试
std::ofstream fout("test.txt");
fout << "test";
fout.close();
FILE *file =NULL;
errno_t err = fopen_s(&file,"test.txt","a");
if(NULL != file){
fflush(file);
_commit(_fileno(file))
fclose(file);
}
linux 系统没有 _commit 系统调用
在 Linux 系统中,commit
系统调用通常与事务型文件系统如 XFS、Btrfs 以及某些数据库的实现相关,而不是直接作为一个独立于这些系统的通用系统调用。在传统的文件系统(如 ext4)中,并没有直接的 commit
系统调用。不过,你可以通过其他机制来达到类似的效果,尤其是在涉及持久化数据更新的场景中。
理解 commit
的概念
在事务型文件系统中,commit
操作通常指的是确保所有自上次 commit
以来进行的写操作都被物理地写入磁盘。这对于数据库和需要高可靠性的应用程序尤其重要。