我一直认为,WriteFile的比FWRITE更有效,因为FWRITE再叫内部WriteFile的,但下面的测试代码显示我的fwrite快显著比WriteFile的。
fwrite的成本为2毫秒,而WriteFile的需要27000(FILE_ATTRIBUTE_NORMAL),都刷新每次写入调用之后。 如果我打电话的WriteFile与FILE_FLAG_WRITE_THROUGH,并发表意见FlushFileBuffers(wfile)线,WriteFile的会更快,它的成本800。
因此,它是真的FWRITE再叫WriteFile的? 是什么让如此巨大的差异? 如何fwrite的内部工作? 我怎么能写数据与API到文件比更有效地使用fwrite?(unbufferd,同步)。
#include <Windows.h>
#include <stdio.h>
#include <iostream>
int main() {
FILE* cfile = fopen("file1.txt", "w");
HANDLE wfile = CreateFile("file2.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
/*FILE_ATTRIBUTE_NORMAL*/FILE_FLAG_WRITE_THROUGH, NULL);
DWORD written = 0;
DWORD start_time, end_time;
char * text = "test message ha ha ha ha";
int size = strlen(text);
int times = 999;
start_time = timeGetTime();
for(int i = 0; i < times; ++i) {
fwrite(text, 1, size, cfile);
fflush(cfile);
}
end_time = timeGetTime();
std::cout << end_time - start_time << '\n';
start_time = timeGetTime();
for(int i = 0; i < times; ++i) {
WriteFile(wfile, text, size, &written, NULL);
//FlushFileBuffers(wfile);
}
end_time = timeGetTime();
std::cout << end_time - start_time << std::endl;
system("pause");
return 0;
}
更新:谢谢你的答案,这里是答案:看VS目录\ VS \ CRT \ SRC \ fflush.c:
//fflush.c
int __cdecl _fflush_nolock (FILE *str) {
//irrelevant codes
if (str->_flag & _IOCOMMIT) {
return (_commit(_fileno(str)) ? EOF : 0);
}
return 0;
}
所以这里是一个_IOCOMMIT标志,再看看... \ SRC \ fdopen.c
FILE * __cdecl _tfdopen (int filedes, const _TSCHAR *mode) {
//irrelevant codes
while(*++mode && whileflag)
switch(*mode) {
//...
case _T('c'):
if (cnflag)
whileflag = 0;
else {
cnflag = 1;
fileflag |= _IOCOMMIT;
}
break;
//...
}
_tfopen由FOPEN内部调用,指的FOPEN的文件,我觉得这样的:
“模式” C'
启用使文件缓冲区的内容直接写入到磁盘如果任fflush或_flushall被调用相关的文件名提交标志。”所以,_commit只有当调用的fopen当‘C’标志设置调用。
该_commit函数最终调用FlushFileBuffers。
除了这些,我发现,当我只写了几个数据文件(不超过缓冲区大小),如果没有FWRITE fflush,文本将不会明显wrritten,而对于API,WriteFile的后即使我不叫FlushFileBuffers ,当我打开文件(程序处于休眠),内容被写入文件自动,这是为什么我很困惑大致齐平的原因之一,此操作可通过操作系统来实现,WriteFile的数据复制到系统缓存,和其文件缓冲区由操作系统管理,所以这是合理的是fflush()只调用WriteFile的内部没有真正的冲洗,系统知道何时刷新他们,也许当文件句柄被关闭或当发生到这个文件中的另一个I / O访问。 所以我修改了基准为这样的:
start_time = timeGetTime();
for(int i = 0; i < times; ++i) {
fwrite(text, 1, size, cfile);
fflush(cfile);
}
end_time = timeGetTime();
std::cout << end_time - start_time << '\n';
start_time = timeGetTime();
for(int i = 0; i < times; ++i) {
WriteFile(wfile, text, size, &written, NULL);
}
end_time = timeGetTime();
std::cout << end_time - start_time << std::endl;
结果是次数:99999的fwrite:217 WriteFile的:171
所以,综上所述,加快API文件书面方式操作:
不要调用FlushFileBuffers明确,在需要时系统缓存的数据将被刷新到磁盘。
获取WriteFile的一个缓冲,就像FWRITE做,因为API调用花费更多的时间比单纯的memcpy,调用WriteFile的当缓冲区填满。