duo*_*gja 5 c++ stdio file-handling
我写了一个程序,将两个小文件压缩成一个更大的文件.我首先从输入文件读取数据,合并数据,并将输出写入临时文件.完成后,我将临时文件重命名为所需的文件名(位于磁盘上的同一分区中).这是伪代码:
FILE* fp_1 = fopen("file_1.dat", "r+b");
FILE* fp_2 = fopen("file_2.dat", "r+b");
FILE* fp_out = fopen("file_tmp.dat", "w+b");
// 1. Read data for the key in two files
const char* data_1 = ...;
const char* data_2 = ...;
// 2. Merge data, store in an allocated buffer
// 3. Write merged buffer to temp file
fwrite(temp_buff, estimated_size, 1, fp_out);
fflush(fp_out);
fclose(fp_1);
fclose(fp_2);
fclose(fp_out);
// Now rename temp file to desired file name
if(std::rename("file_tmp.dat", "file_out.dat") == 0)
{
std::remove("file_1.dat");
std::remove("file_2.dat");
}
Run Code Online (Sandbox Code Playgroud)
我用两个每个5 MB的输入文件反复测试程序.有一次我通过拔掉电源线突然关闭系统.重新启动系统后,我检查了数据,发现输入文件已被删除,并且file_out.dat全部为零.这让我相信系统在删除了2个输入文件之后立即关闭,输出数据仍然在磁盘控制器缓冲区的某处.如果这是真的,那么有什么方法可以检查数据是否已实际写入磁盘?
不是一般情况.磁盘可以骗到操作系统,声称写入完成时,它实际上只是在硬盘驱动器的板载RAM缓存中排队,这将在突然断电时丢失.
你能做的最好的明确要求OS告诉磁盘你执行后"真的,真的同步一切" fflush,无论是范围有限用fsync或使用类似的sync或syncfs(前同步所有文件系统,后者限制了范围到与单个文件描述符对应的文件系统).您希望fsync在最终之后fflush但是之前rename和/或更广泛sync/ syncfs之后rename但在remove调用之前执行目标,以便在删除源文件之前明确更新数据和文件系统表.
当然,就像我说的,这是最好的努力; 如果磁盘控制器正在向操作系统说谎,那么就没有什么可以羞于为磁盘编写新的固件和驱动程序,这可能太过分了.