c++ 写入文件不频繁打开_C/C++编程笔记:你不知道的windows保存文件的坑

对于c/c++来说,写文件是必不可少的事情。但是如果大家不仔细研究,真的会掉进某些坑里。

在某些紧急情况下,可能要保证数据安全且及时的写到磁盘上,否则就会有丢失的风险。

小文件可能还不那么明显,对于大文件来说,按照平常的方式,可能就出事了。

今天我就带大家来聊一聊这个问题。

66d17e5f014c52f9473411ca0d4ed217.png

读写文件

c语言中文件操作用的是 FILE*, 以及与之相关的打开,读,写,关闭等函数。

对应的是 fopen、fread、fwrite、fclose 等(fgets fputs 等就不在此继续展开了)。

但是在写文件的时候,我们如何保证数据被正确及时的写到磁盘上面了呢?

可能大家会说调用 fflush;很显然如果真的是这样,那今天我也不会写这篇文章了。

那为什么 fflush 不对呢?

缓存

我们可能都知道,文件读写,或者说一般的IO操作都会有缓存。

即磁盘文件被操作系统映射到系统的某个内存中缓存了;我们平常读写是会和缓存打交道。

操作系统根据我们当前操作情况,在缓存与磁盘文件之间进行数据交互。

而对于 fflush 来说,只能保证数据已经被写到了操作系统的文件缓存,不能保证已经写到了磁盘!

只有在 fclose 的时候才能确保缓存数据全部写到磁盘,然后关闭文件。

大家可能会问,那就在 fwrite 写完数据后,直接 fclose 不就行了。

是的,对于小文件来说可能确实如此。

但是对于大文件的时候,可能之前缓存里的数据还没有及时写到磁盘,后面的数据也需要写入;

虽然在 fclose 后会强制将缓存数据写到磁盘,但是可能会需要一点时间,而不巧此时断电了。

解决方案

windows提供的API中,有 CreateFile、ReadFile、WriteFile 和 CloseHandle 来处理IO操作。

其中 CreateFile 有个 dwFlagsAndAttributes 的参数,可以传递不同的属性。

对于我们遇到的问题可以向该参数设置为 FILE_FLAG_NO_BUFFERING 或 FILE_FLAG_WRITE_THROUGH 或者设置成它们相或后的值。

FILE_FLAG_NO_BUFFERING 表示读写文件时,不创建缓存;

FILE_FLAG_WRITE_THROUGH 表示在数据写到缓存后,立刻写入磁盘。

即要写入的文件如下打开即可:

// 打开文件HANDLE hFileDst = ::CreateFileA(dst.toLocal8Bit().data(),                             GENERIC_WRITE,                             0,                             NULL,                             OPEN_ALWAYS,                             /*FILE_FLAG_NO_BUFFERING |*/ FILE_FLAG_WRITE_THROUGH, // 设置flag                             NULL);    if (hFileDst == INVALID_HANDLE_VALUE)    {        CloseHandle(hFileSrc);        return;    }// 数据写入int ret = ::WriteFile(hFileDst, m_dat, dwReadSize, &dwWriteSize, NULL);

需要注意的是 FILE_FLAG_NO_BUFFERING 设置后需要字节对应,文件存取的字节数必须是扇区尺寸的整倍数。

例如,如果扇区尺寸是512字节,程序就可以读或者写512,1024或者2048字节,但不能够是335,981或者7171字节。(这是MSDN上的翻译)

总结

缓存的存在是操作系统为了更好方便我们读写数据,避免因为磁盘的慢速,影响读写操作;

但是如果不清楚其中的原理,可能在特殊情况时,不知道如何处理问题。

当然如果大家没有紧急情况出现,或者对数据写入时间不敏感,可以直接忽略;还是用标准写文件的方式,毕竟更加通用。

如果觉得我写的还不错的话,求赞,求关注哦!(^▽^)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值