检查文件内容是否已实际写入磁盘 - 未在磁盘控制器的缓冲区中排队

时间:2016-09-30 03:30:41

标签: c++ file-handling stdio

我写了一个程序,将两个小文件压缩成一个更大的文件。我首先从输入文件读取数据,合并数据,并将输出写入临时文件。完成后,我将临时文件重命名为所需的文件名(位于磁盘上的同一分区中)。这是伪代码:

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");
}

我用两个5 MB的输入文件反复测试程序。有一次我通过拔掉电源线突然关闭了系统。重新启动系统后,我检查了数据,发现输入文件已被删除,file_out.dat填充了所有零。这让我相信系统在删除了2个输入文件之后立即关闭,输出数据仍在磁盘控制器缓冲区中的某个位置。如果这是真的,那么有什么方法可以检查数据是否已实际写入磁盘?

1 个答案:

答案 0 :(得分:5)

不是一般情况。磁盘可以骗到操作系统,声称写入完成时,它实际上只是在硬盘驱动器的板载RAM缓存中排队,这将在突然断电时丢失。

您可以做的最好的事情就是明确要求操作系统在您执行fflush之后告诉磁盘“真正地,真正地同步所有内容”,使用fsync限制范围或使用类似的内容sync or syncfs(前者同步所有文件系统,后者将范围限制为对应于单个文件描述符的文件系统)。您希望在最终fsync之后但在fflush之前和/或rename / syncsyncfs之后执行定位rename remove 1}}但在mainVC调用之前,所以在删除源文件之前,数据和文件系统表肯定会更新。

当然,就像我说的,这是最好的努力;如果磁盘控制器正在向操作系统说谎,那么你就无法为磁盘编写新的固件和驱动程序,这可能太过分了。