gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:28:19 27 4
gpt4 key购买 nike

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

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 个输入文件后立即崩溃,并且输出数据仍在磁盘 Controller 缓冲区中的某个位置。如果这是真的,那么有什么方法可以检查数据是否已实际写入磁盘?

最佳答案

一般情况下不会。即使您告诉操作系统等待数据写入(使用 sync API 系列),一些磁盘也会向操作系统撒谎,声称写入已完成,而实际上它只是在硬盘驱动器的板载 RAM 中排队缓存,这将在突然断电时丢失。

你能做的最好的事情就是在你执行完 fflush 之后明确要求操作系统告诉磁盘“真的,真的同步所有东西并阻塞直到它完成”(这只告诉 stdio将所有用户模式缓冲数据发送到操作系统的库,操作系统通常将其保存在内核缓冲区中,并稍后在后台将内核缓冲区同步到磁盘),fsync 的范围有限或使用类似 sync or syncfs 的东西(前者同步所有文件系统,后者将范围限制为单个文件描述符对应的文件系统)。

为了最大程度的安全,您需要:

  1. 在最后的 fflush 之后但在 rename 之前执行有针对性的 fsync(因此新文件在替换旧文件之前已在磁盘上完成), 和
  2. rename 之后但在 remove 调用之前执行更广泛的 sync/syncfs(以便元数据更新从 rename 删除源文件之前完成)

如果您不介意在输入数据仍然存在的情况下损坏输出数据,则可以省略第 1 步。

当然,就像我说的,这都是尽力而为;如果磁盘 Controller 对操作系统说谎,那么您只能为磁盘编写新的固件和驱动程序,这可能太过分了。

关于c++ - 检查文件内容是否已实际写入磁盘 - 未在磁盘 Controller 的缓冲区中排队,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39783216/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com