使用FILE_FLAG_NO_BUFFERING等标志时ReadFile报‘参数不正确’错误求助
使用FILE_FLAG_NO_BUFFERING + FILE_FLAG_WRITE_THROUGH读取文件的解决方法(MSVC)
问题出在FILE_FLAG_NO_BUFFERING的严格约束上——这个标志要求读写操作必须完全对齐到磁盘扇区大小,违反任何一条都会导致ReadFile调用失败。以下是具体要求和修正方案:
必须满足的对齐规则
- 读写缓冲区的内存地址必须是磁盘扇区大小的整数倍
- 每次读写的字节数必须是磁盘扇区大小的整数倍
- 文件指针的偏移量必须是磁盘扇区大小的整数倍
分步修正实现
1. 获取目标磁盘的扇区大小
不同磁盘的扇区大小可能不同(常见为512或4096字节),用GetDiskFreeSpace函数获取:
DWORD sectorSize = 0; DWORD bytesPerCluster, freeClusters, totalClusters; if (!GetDiskFreeSpaceW(L"C:\\", &bytesPerCluster, §orSize, &freeClusters, &totalClusters)) { printf("GetDiskFreeSpace failed: %lu\n", GetLastError()); return 1; }
2. 分配对齐的缓冲区
普通栈内存、malloc/new无法保证地址对齐到扇区大小,MSVC下使用_aligned_malloc分配对齐内存:
DWORD bufferSize = sectorSize * 2; // 按2个扇区大小分配,可按需调整 char* buffer = (char*)_aligned_malloc(bufferSize, sectorSize); if (!buffer) { printf("Aligned buffer allocation failed\n"); // 资源清理 return 1; }
3. 确保读写操作对齐
- 读取字节数必须是扇区大小的整数倍
- 若文件大小不是扇区倍数,最后一次读取需特殊处理(读取完整扇区后截断到实际剩余字节):
// 获取文件大小 LARGE_INTEGER fileSize; if (!GetFileSizeEx(hFile, &fileSize)) { printf("GetFileSizeEx failed: %lu\n", GetLastError()); // 资源清理 return 1; } DWORD bytesLeft = (DWORD)fileSize.QuadPart; while (bytesLeft > 0) { DWORD readSize = min(bufferSize, bytesLeft); if (readSize < sectorSize) { // 移动到最后一个完整扇区的起始位置 LARGE_INTEGER pos; pos.QuadPart = fileSize.QuadPart - sectorSize; SetFilePointerEx(hFile, pos, NULL, FILE_BEGIN); readSize = sectorSize; ReadFile(hFile, buffer, readSize, &bytesRead, NULL); // 仅使用前bytesLeft字节 printf("Read final %lu bytes\n", bytesLeft); bytesLeft = 0; } else { ReadFile(hFile, buffer, readSize, &bytesRead, NULL); bytesLeft -= bytesRead; printf("Read %lu bytes, remaining %lu\n", bytesRead, bytesLeft); } }
4. 正确打开文件
确保打开参数组合正确,FILE_FLAG_NO_BUFFERING需搭配GENERIC_READ(或读写权限),且不要与冲突标志混用:
HANDLE hFile = CreateFileW( filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL ); if (hFile == INVALID_HANDLE_VALUE) { printf("CreateFile failed: %lu\n", GetLastError()); return 1; }
完整修正示例代码
#include <windows.h> #include <stdio.h> #include <malloc.h> int main() { const wchar_t* filePath = L"C:\\test.bin"; DWORD sectorSize = 0; DWORD bytesPerCluster, freeClusters, totalClusters; // 获取磁盘扇区大小 if (!GetDiskFreeSpaceW(L"C:\\", &bytesPerCluster, §orSize, &freeClusters, &totalClusters)) { printf("GetDiskFreeSpace failed: %lu\n", GetLastError()); return 1; } // 打开文件 HANDLE hFile = CreateFileW( filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL ); if (hFile == INVALID_HANDLE_VALUE) { printf("CreateFile failed: %lu\n", GetLastError()); return 1; } // 分配对齐缓冲区 DWORD bufferSize = sectorSize * 2; char* buffer = (char*)_aligned_malloc(bufferSize, sectorSize); if (!buffer) { printf("Aligned malloc failed\n"); CloseHandle(hFile); return 1; } // 获取文件大小并处理读取 LARGE_INTEGER fileSize; if (!GetFileSizeEx(hFile, &fileSize)) { printf("GetFileSizeEx failed: %lu\n", GetLastError()); _aligned_free(buffer); CloseHandle(hFile); return 1; } DWORD bytesLeft = (DWORD)fileSize.QuadPart; DWORD bytesRead; while (bytesLeft > 0) { DWORD readSize = min(bufferSize, bytesLeft); if (readSize < sectorSize) { LARGE_INTEGER pos; pos.QuadPart = fileSize.QuadPart - sectorSize; if (!SetFilePointerEx(hFile, pos, NULL, FILE_BEGIN)) { printf("SetFilePointerEx failed: %lu\n", GetLastError()); break; } readSize = sectorSize; if (!ReadFile(hFile, buffer, readSize, &bytesRead, NULL)) { printf("ReadFile failed: %lu\n", GetLastError()); break; } printf("Read final %lu bytes (from %lu-byte sector)\n", bytesLeft, bytesRead); bytesLeft = 0; } else { if (!ReadFile(hFile, buffer, readSize, &bytesRead, NULL)) { printf("ReadFile failed: %lu\n", GetLastError()); break; } bytesLeft -= bytesRead; printf("Read %lu bytes, remaining %lu\n", bytesRead, bytesLeft); } } // 清理资源 _aligned_free(buffer); CloseHandle(hFile); return 0; }
内容的提问来源于stack exchange,提问作者BasioKar
相关产品推荐
相关产品推荐

