Win64下使用ReadFile读取大于2GB完整文件的问题
解决Win64下大文件整读的限制问题
核心问题分析
你的代码存在两个关键的类型适配问题:
ReadFile的第三个参数nNumberOfBytesToRead要求为DWORD(32位无符号整数,最大值为4294967295字节,约4GB),你传入的long long类型值会被隐式截断——尽管当前文件在3.1GB以内(小于DWORD最大值),但这种写法存在潜在风险;bytesRead为DWORD类型,若未来文件大小超过4GB,会直接导致溢出,无法正确记录读取的总字节数。
此外代码缺少基础错误检查,比如文件是否打开成功、内存是否分配成功,这些都可能引发程序崩溃或异常。
针对性解决方案
1. 适配当前文件场景的修正代码
针对1.1GB-3.1GB的文件范围,修改代码以匹配API参数要求,同时补充必要的错误判断:
#include <Windows.h> #include <iostream> using namespace std; int main() { cout << "start\r\n"; // 打开文件,添加共享读取权限,避免独占文件导致其他进程无法访问 HANDLE hInput = CreateFile(L"My-giant-File.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hInput == INVALID_HANDLE_VALUE) { cout << "打开文件失败,错误码: " << GetLastError() << endl; return 1; } // 获取文件实际大小,避免分配多余内存 LARGE_INTEGER fileSize; if (!GetFileSizeEx(hInput, &fileSize)) { cout << "获取文件大小失败,错误码: " << GetLastError() << endl; CloseHandle(hInput); return 1; } // 校验文件大小是否在预期区间内 const LONGLONG MIN_SIZE = 1181116006; // 1.1GB对应的字节数 const LONGLONG MAX_SIZE = 3323008000; // 3.1GB对应的字节数 if (fileSize.QuadPart < MIN_SIZE || fileSize.QuadPart > MAX_SIZE) { cout << "文件大小超出预期范围" << endl; CloseHandle(hInput); return 1; } // 分配内存,Win64下malloc支持大内存分配(必须确保是64位编译) byte* buffer = reinterpret_cast<byte*>(malloc(fileSize.QuadPart)); if (!buffer) { cout << "内存分配失败" << endl; CloseHandle(hInput); return 1; } DWORD bytesRead = 0; // 文件大小<=3.1GB,小于DWORD最大值,直接强转后传递 if (!ReadFile(hInput, buffer, static_cast<DWORD>(fileSize.QuadPart), &bytesRead, NULL)) { cout << "读取文件失败,错误码: " << GetLastError() << endl; free(buffer); CloseHandle(hInput); return 1; } // 验证读取字节数是否匹配文件大小 if (static_cast<DWORD>(fileSize.QuadPart) != bytesRead) { cout << "未完成读取:仅读取" << bytesRead << "字节,文件总大小" << fileSize.QuadPart << "字节" << endl; } // 执行数据处理操作 free(buffer); CloseHandle(hInput); cout << "操作完成" << endl; return 0; }
2. 超4GB文件的扩展读取方案(可选)
如果未来需要处理超过4GB的文件,即使想整读,也需要用ULARGE_INTEGER记录总读取字节数,结合循环读取(ReadFile单次最多读取4GB):
// 省略文件打开、内存分配等前置代码... ULARGE_INTEGER totalBytesRead = {0}; DWORD bytesReadPerCall = 0; byte* currentBuffer = buffer; LARGE_INTEGER remainingBytes = fileSize; while (remainingBytes.QuadPart > 0) { // 每次读取不超过DWORD最大值 DWORD readSize = remainingBytes.QuadPart > DWORD_MAX ? DWORD_MAX : static_cast<DWORD>(remainingBytes.QuadPart); if (!ReadFile(hInput, currentBuffer, readSize, &bytesReadPerCall, NULL)) { cout << "读取失败,错误码: " << GetLastError() << endl; break; } totalBytesRead.QuadPart += bytesReadPerCall; currentBuffer += bytesReadPerCall; remainingBytes.QuadPart -= bytesReadPerCall; if (bytesReadPerCall != readSize) { cout << "提前到达文件末尾" << endl; break; } } // 验证总读取字节数 if (totalBytesRead.QuadPart != fileSize.QuadPart) { cout << "读取不完整:" << totalBytesRead.QuadPart << "/" << fileSize.QuadPart << endl; }
3. 关键注意事项
- 必须以64位模式编译程序:Win32程序的虚拟地址空间最大仅2GB左右,无法容纳3GB级别的内存缓冲区;
- 严格处理内存分配失败:大内存分配存在失败概率,必须检查
malloc的返回值; - 文件权限设置:打开文件时添加
FILE_SHARE_READ,避免独占文件导致其他进程无法访问。
内容的提问来源于stack exchange,提问作者Kenneth Hippolite
相关产品推荐
相关产品推荐

