注意, 该操作存在风险(数据可能会丢失), 谨慎操作
注意, 该操作存在风险(数据可能会丢失), 谨慎操作
注意, 该操作存在风险(数据可能会丢失), 谨慎操作
note
- 1 实际使用场景中, 会出现,写文件过程中, 将驱动器从主机上断开,再重新插上一块新的驱动器(移动硬盘)
- 2 未知:当断开驱动器时, 此时依然执行 fwrite函数写入文件, 文件是否能写入成功, 特作此实验
- 3 其他平台,没有测试。
环境
- windows11 64
- VS 2019
- U 盘模拟移动硬盘
- fwrite 写入文件测试
- 请阅读 fflush
- 写同名文件测试
基于此次测试结论
- fwrite 仅仅将数据写入 文件缓冲, 将数据写入文件 得 fflush 函数
- 当写一个文件时, 中途取下U盘, 内核无法将缓存的数据写入文件, 即 调用fflush函数将失败, frwite 成功
- 当写一个文件时,中途取下U盘,再次执行同名文件写入, 依然能将数据写入磁盘(本次测试中,创建文件使用的 "W"方式)
- 当写一个文件时, 如果中途取下U盘, 再插入, 后面的数据依然无法写入成功
- 当两个文件时, 第一个文件写入成功, 第二个文件写入失败(写入中途取下U盘), 模拟磁盘上存在其他文件, 重新插上U盘, 待系统修复U盘结束后, 第一个文件中的数据存在,第二个文件或无法打开 或 文件内容不全等
准备代码
1 准备测试代码
- 测试代码如下,创建文件, 循环20次, 将数据一段固定数据写入文件
void call_write(const std::string& file_name)
{
FILE* pfile = nullptr;
errno_t ret = fopen_s(&pfile, file_name.c_str(), "w+");
if (0 != ret)
{
std::cout << "\n 11111 ret=" << ret << "\n";
return ;
}
const char parr[]{ "1234567890\n" };
const size_t len = strlen(parr);
for (int index = 0; index < 20; ++index)
{
if (len != fwrite(parr, 1, len, pfile))
{
std::cout << "22222, index << " << index << ", error_id=" << ferror(pfile) << "\n";
break;
}
else
{
std::cout << "index=" << index << " succeeded to call fwrite, ";
}
int ret = fflush(pfile);
std::cout << ", fflush_ret =" << ret << "\n";
std::this_thread::sleep_for(std::chrono::seconds(2));
}
fclose(pfile);
pfile = nullptr;
}
3. 准备测试U盘
测试情景1
1. 当正在写入文件途中,将驱动器取下
int main()
{
/// 1. 文件测试1
call_write(std::string("E:\\1.txt"));
return 0;
}
2. 情景1 输出结果
- 当 输出
index=3
时, 将U盘取下来,此时console
输出结果
- 可见, 当index=3输出后(此时已经取下U盘), 发现后面的7次 调用 fwrite 函数均成功, 但是, 调用 fflush 却失败了(返回值为 -1, )。 因为驱动器不在了, 无法将缓冲中的数据写入磁盘。 故而失败。
3. 文件内容
- 既然存在写入成功,重新插上U盘,打开文件, 查看文件内容(灾难, )
- 系统修复后, 可查看文件内容, 不过, 文件内容, 或为空, 或存在几行数据, 我测试了多次, 结果不一 , 其中一次情况如下:
- 可见, 尽管程序执行了至少2次成功的fflush的调用, 但是修复后的文件中, 只有一行数据
测试情景2
1. 先创建文件,再将驱动器取下, 最后插上
- 测试用例要写入20次, 20次内, 依次 完成, 先写入, 再取下, 最后插入的过程。
- 输出index=2, 取下U盘, 输出 index=6, 插上U盘。 观察20次执行 结束后,的输出结果
情景2 输出结果
- 可见, 当取下U盘后,index=3~index=5的过程中, 调用 fwrite 成功, 但是,调用fflush 失败, index=6 开始,后面的 fwrite 都成功, fflush调用失败
- 结论,当U盘中途断开后, 尽管再次将U盘插上, 后面的写入依然无法成功
测试情景3
-
- 改调用代码如下, 写入两个文件, 当主线程main函数中睡眠10s时,开始将盘取下, 10s到之前, 将U盘再插入
int main()
{
/// 1. 文件测试1
call_write(std::string("E:\\1.txt"));
/// 主线程暂停, 重新插上U盘
std::cout << "\n\n ====================== main_thread pause begin ======================= \n\n";
std::this_thread::sleep_for(std::chrono::seconds(1 * 10));
std::cout << "\n\n ====================== main_thread pause ended ======================= \n\n";
/// 2. 文件测试2
call_write(std::string("E:\\2.txt"));
return 0;
}
2. 输出结果
- 可见,两个文件写入全部成功, fwrite和fflush调用全部成功
3. 打开写入的文件
- 可见, 文件写入成功
测试情景4
1. 写两个文件, 第一个文件 最后 13次时, 取下U盘, 格式化, 待到创建第二个文件前,,再插入U盘, 直到第二个文件20次写入结束
2. 输出结果
3. 分析
- 这里, 多了一个格式化的步骤, 因为插上U盘, 系统提示驱动器存在问题,需要修复。
- 可见,当创建第二个文件前, 保证驱动器时OK的, 文件可以创建成功并写入成功
- 文件内容如下
4. 进一步测试
- 如果不执行格式化呢?
- 输出结果
- 可见, 依然成功
测试情景5
1. 步骤:写一个文件, 写文件执行到中途,取下U盘, 再将U盘插上, 此时,执行结果
取下U 盘后,此时写入失败,
插上U盘, 再次执行程序写入同名文件, 此时结果
可见依然能写入成功