c++ - fwrite 比 Windows 中的 WriteFile 快吗?

2025-07-08 00:21:12

我一直认为 WriteFile 比 fwrite 效率更高,因为 fwrite 在内部调用了 WriteFile,但是下面的测试代码告诉我 fwrite 比 WriteFile 快得多。

fwrite 花费 2 毫秒,而 WriteFile 需要 27000(FILE_ATTRIBUTE_NORMAL),每次写入调用后都会刷新。如果我用 FILE_FLAG_WRITE_THROUGH 调用 WriteFile,并注释 FlushFileBuffers(wfile) 行,WriteFile 会更快,它花费 800。

那么 fwrite 真的会调用 WriteFile 吗?是什么造成了如此巨大的差异?fwrite 在内部是如何工作的?如何使用 API 比 fwrite 更有效地将数据写入文件?(无缓冲,同步)。

#include

#include

#include

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 directory\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 时将文件缓冲区的内容直接写入磁盘。”因此,只有在调用 fopen 时设置了 'c' 标志时才会调用 _commit。

_commit 函数最终调用 FlushFileBuffers。

除此之外,我发现当我只向文件写入少量数据时(不超过缓冲区大小),如果 fwrite 没有 fflush,则文本显然不会被写入,而对于 API,即使我不调用 FlushFileBuffers,在 WriteFile 之后,当我打开文件(程序处于睡眠状态)时,内容会自动写入文件,这就是我对 flush 感到困惑的原因之一,这个操作可能是由操作系统完成的,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。

怎么改手机短信背景 如何把手机短信背景设置成自己喜欢?
五笔编码:提用五笔怎么打