我正在处理Windows上的文件映射,但是遇到了一些问题。 首先,我需要部分映射一个文件,并动态设置其开始和结束位置。
我的代码如下:
long fiveMB = 5 * pow(2, 20);
for(int i=0;i<parts;i++){
long start = (i)*fiveMB;
long end = (i + 1)*fiveMB;
long realEnd = end;
if (roundedDim<realEnd)
realEnd = dim;
long chunkDim = realEnd - start;
LARGE_INTEGER fileMapStart.QuadPart = (start/granularity)*granularity;
LARGE_INTEGER mapViewSize.QuadPart = (start%granularity) + chunkDim;
LARGE_INTEGER fileMapSize.QuadPart = start + chunkDim;
long offset = start - fileMapStart.QuadPart;
HANDLE fileMappingH= CreateFileMapping(fileH, NULL, PAGE_READONLY, fileMapSize.HighPart, fileMapSize.LowPart, NULL);
if(fileMappingH == INVALID_HANDLE_VALUE || fileMappingH == NULL){
printf("Error mapping file: %d\n",GetLastError());
CloseHandle(fileH);
return 1;
}
char *mapView = (char *)MapViewOfFile(fileMappingH, FILE_MAP_READ, fileMapStart.HighPart, fileMapStart.LowPart, mapViewSize.QuadPart);
if ((LPVOID)mapView == NULL) {
printf("Error mapView: %d\n", GetLastError());
CloseHandle(fileMappingH);
CloseHandle(file);
return 1;
}
mapView += offset;
/* doing all the stuff */
UnmapViewOfFile((LPVOID)mapView);
CloseHandle(fileMappingH);
}
据我所知,只有MapViewOfFile需要起始字节与系统粒度对齐,因此我没有费心为此修复最大文件映射大小。
我在一个1448 KB的文件上尝试了这段代码(打印出dim后得到1482159个字节),通过GlobalMemoryStatusEx(&memstatus)和memstatus.ullAvailVirtual计算可用内存,我得到了2092208128个字节,但仍然遇到了CreateFileMapping调用失败并出现错误代码8,ERROR_NOT_ENOUGH_MEMORY。
我还尝试调用CreateFileMapping(fileH, NULL, PAGE_READONLY, 0, 0, NULL)来内存映射整个文件,但是MapViewOfFile出现了问题,错误5,ERROR_ACCESS_DENIED。
我不明白我在这里做错了什么,因为我在同一项目的Linux版本中成功地使用mmap进行了操作。
感谢任何能够提供帮助的人。
编辑:
- c是一个遗留下来的东西,我实际上是指i。 - 添加了UnmapViewOfFile和CloseHandle调用。
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlGetLastNtStatus();
并链接到ntdll.lib
或在运行时获取此过程地址,如GetProcAddress(GetModuleHandle(L"ntdll"), "RtlGetLastNtStatus");
,并在MapViewOfFile
失败后调用它 - 因为太多不同的状态映射到ERROR_ACCESS_DENIED
- 使用GetLastError
会丢失太多有用的信息。 - RbMmSTATUS_INVALID_VIEW_SIZE
,STATUS_ALREADY_COMMITTED
,STATUS_ACCESS_DENIED
- all this is converted toERROR_ACCESS_DENIED
. i for example guess that you gotSTATUS_INVALID_VIEW_SIZE
- RbMmMapViewOfFile
调用指定的; 因此,如果您知道正确的文件偏移量以及从那里检查多少字节,只需通过正确指定MapViewOfFile
的最后一个参数来执行此操作,我的代码中为mapViewSize.QuadPart
。在这里您可以看到整个代码,链接到特殊的MapViewOfFile
函数调用。 - Emanuele GionaCreateFileMapping
中必须放入整个文件大小;为了检查给定偏移量处的3个字节,必须通过MapViewOfFile
指定。请注意,此类调用涉及的每个大小都必须与文件系统粒度对齐!因此,如果要读取这3个字节,您必须映射一个正确从所期望的粒度开始的文件块,其大小为3个字节,然后考虑偏移量来定位这些字节。 - Emanuele Giona