序
对于c/c++来说,写文件是必不可少的事情。但是如果大家不仔细研究,真的会掉进某些坑里。
在某些紧急情况下,可能要保证数据安全且及时的写到磁盘上,否则就会有丢失的风险。
小文件可能还不那么明显,对于大文件来说,按照平常的方式,可能就出事了。
今天我就带大家来聊一聊这个问题。

读写文件
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上的翻译)
总结
缓存的存在是操作系统为了更好方便我们读写数据,避免因为磁盘的慢速,影响读写操作;
但是如果不清楚其中的原理,可能在特殊情况时,不知道如何处理问题。
当然如果大家没有紧急情况出现,或者对数据写入时间不敏感,可以直接忽略;还是用标准写文件的方式,毕竟更加通用。
相关文章:
唐朝吃相最难看的贪官,修祖坟累死县令,要升官献上妹子 04-15
科普:明朝流通的货币体系主要有哪些? 04-15
揭秘明朝五大军备神器,战无不胜攻无不克 04-15
明朝内阁制的演变过程:逐渐从一个秘书机构演变为行政机构 04-15
北宋汴梁是现在的哪个城市?北宋皇帝办公的地,一起来看看吧 04-15
C/C++编程笔记:你不知道的windows保存文件的坑 04-14
唐朝的地理位置? 唐朝巅峰时期版图最西到达哪里?千万不要被谭版地图给骗了 04-14
明朝南北榜案,不是科场舞弊案,朱元璋为什么要惩罚南方文人官僚? 04-14
为何明朝皇权明明是加强,明朝的言官们反而更有战斗欲? 04-14
明朝不为人知的北元,苟延残喘下的蒙古贵族 04-14