写入文件后不关闭句柄直接计算MD5哈希结果错误的技术问询
不关闭文件句柄计算MD5哈希结果错误的解决办法
问题描述
我在写入文件后直接计算其MD5哈希,代码如下:
std::wstring filePath = L"file.txt"; auto hFile = CreateFile( filePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); // 使用WriteFile(hFile, buffer, DWORD(size), &written, NULL)写入文件
关闭文件再重新打开计算MD5是正常的,但我希望不关闭句柄就完成计算。于是尝试保存当前文件指针位置,移动到文件开头计算MD5后再恢复指针:
LARGE_INTEGER liOfs = {0}; LARGE_INTEGER liNew = {0}; SetFilePointerEx(hFile, liOfs, &liNew, FILE_CURRENT); SetFilePointer(hFile, 0, NULL, FILE_BEGIN); auto md5 = CalculateMd5(hFile); // 此处MD5结果错误 // 恢复指针 SetFilePointerEx(hFile, liNew, NULL, FILE_BEGIN); CloseHandle(hFile);
之前的CloseHandle(hFile)异常(错误码0xC0000008)已通过解决重复关闭句柄问题修复,但现在不关闭句柄计算出的MD5是d41d8cd98f00b204e9800998ecf8427e(空文件的MD5),而用命令certutil -hashfile test.txt MD5得到的正确结果是1207b6ae90980a5b039d57384b8bbd26。只有关闭再重新打开句柄计算,结果才一致。
问题原因
写入文件后,Windows系统会将数据暂存到文件缓存中,不会立即写入磁盘。此时直接通过文件句柄读取,要么只能读到缓存中未同步到磁盘的内容,要么因为文件指针停在写入后的末尾,读取到空内容,最终计算出空文件的MD5。
解决方法
方法1:写入后调用FlushFileBuffers刷新缓存
在WriteFile完成后,调用FlushFileBuffers将缓存中的数据强制写入磁盘,之后再移动指针计算MD5:
// 写入文件操作 DWORD written; if (!WriteFile(hFile, buffer, DWORD(size), &written, NULL)) { // 处理写入失败逻辑 } // 刷新缓存到磁盘 FlushFileBuffers(hFile); // 保存当前指针位置 LARGE_INTEGER liOfs = {0}; LARGE_INTEGER liNew = {0}; SetFilePointerEx(hFile, liOfs, &liNew, FILE_CURRENT); // 移动到文件开头 SetFilePointer(hFile, 0, NULL, FILE_BEGIN); // 计算MD5 auto md5 = CalculateMd5(hFile); // 恢复指针位置 SetFilePointerEx(hFile, liNew, NULL, FILE_BEGIN); CloseHandle(hFile);
FlushFileBuffers会等待所有数据写入磁盘完成,对于大文件会有一定性能开销,但能确保数据已持久化。
方法2:创建文件时使用FILE_FLAG_WRITE_THROUGH标志
在调用CreateFile时添加FILE_FLAG_WRITE_THROUGH参数,系统会绕过缓存直接将写入数据发送到磁盘,无需额外调用FlushFileBuffers:
auto hFile = CreateFile( filePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_WRITE_THROUGH, NULL);
这种方式会降低写入性能,因为每次写入都直接操作磁盘,适合对数据实时性要求高的场景。
额外注意事项
- 确保
CalculateMd5函数读取文件时的指针处理正确,避免影响后续操作(当前代码已恢复指针,无需担心)。 - 必须检查
WriteFile的返回值,确认写入操作成功,避免因写入失败导致计算空文件MD5。
内容的提问来源于stack exchange,提问作者qloq
相关产品推荐
相关产品推荐

