CreateFileMapping映射大文件失败主因是dwMaximumSizeHigh/Low参数错误:需用GetFileSizeEx获取真实大小并正确拆分高低32位,高位不可省略;新映射时两参数均须非零。

为什么 CreateFileMapping 映射大文件会失败(ERROR_INVALID_PARAMETER)
常见现象是调用 CreateFileMapping 返回 NULL,GetLastError() 得到 ERROR_INVALID_PARAMETER —— 这通常不是权限或路径问题,而是 dwMaximumSizeHigh 和 dwMaximumSizeLow 传错了。Windows 要求这两个参数合起来表示的文件大小不能超过实际文件长度(对已存在文件),也不能为 0(对新创建映射)。更隐蔽的是:如果文件本身大于 4GB,你必须显式指定高位大小,哪怕低位已满 0xFFFFFFFF;只设 dwMaximumSizeLow = 0xFFFFFFFF、高位为 0,系统会当作 4GB 截断,导致参数非法。
- 先用
GetFileSizeEx获取真实大小(返回LARGE_INTEGER),再拆成高低 32 位传入 - 不要手算高位:直接用
size.QuadPart >> 32和(DWORD)size.QuadPart,避免符号扩展错误 - 若映射新文件(
hFile = INVALID_HANDLE_VALUE),则两个 size 参数必须非零,且总大小不能超 2^64−1,但实际建议单次不超过 16TB(NTFS 限制)
MapViewOfFile 失败:访问越界还是地址空间不足?
映射成功后,MapViewOfFile 返回 NULL 并报 ERROR_NOT_ENOUGH_MEMORY,大概率不是物理内存不够,而是用户模式地址空间碎片化或单次映射太大。32 位进程默认只有 2GB 可用虚拟地址(/LARGEADDRESSAWARE 也才 3GB),而一个 8GB 文件无法一次性全映射进去。64 位程序虽地址宽裕,但 Windows 默认仍限制单次 MapViewOfFile 最大约 128GB(取决于系统版本和页表结构)。
- 永远分块映射:比如每次映射 512MB,用
dwFileOffsetLow/dwFileOffsetHigh控制起始位置 - 映射前检查
GetSystemInfo().lpMaximumApplicationAddress,确认剩余可用地址空间 - 务必配对调用
UnmapViewOfFile,否则地址泄漏比内存泄漏更难排查
写入大文件映射区时数据没落盘?
你改了映射内存里的内容,调用 FlushViewOfFile 后仍发现文件没更新,甚至程序崩溃后数据丢失——这往往是因为没触发底层页回写,或者忽略了 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 等属性干扰缓存行为。更关键的是:FlushViewOfFile 只保证数据进入系统缓存,不等于写入磁盘;除非打开文件时用了 FILE_FLAG_NO_BUFFERING(此时要求对齐且绕过缓存,代价极高),否则必须依赖 FlushFileBuffers 才能强制落盘。
- 修改后先调
FlushViewOfFile,再对原始hFile调FlushFileBuffers - 若需高可靠性,打开文件时加
FILE_FLAG_WRITE_THROUGH(禁用驱动层写缓存) - 注意:NTFS 压缩或加密文件不支持内存映射写入,会静默失败
跨进程共享大文件映射要注意句柄继承和名字冲突
用命名映射(lpName 非空)让多个进程访问同一份数据时,常出现“找不到对象”或“拒绝访问”。根本原因不是权限设错,而是:命名空间隔离(如 Win10 的 session 0 隔离)、全局名被占用、或父进程未设 bInheritHandle = TRUE 导致子进程拿不到有效 hFile。另外,命名映射的 lpName 是内核对象名,不走文件系统路径规则,不能含反斜杠(),且长度上限 260 字符。
- 命名推荐格式:
"Local\MyBigData_0x12345678"(Local\表示当前 session,避免全局污染) - 若需父子进程通信,父进程创建
hFile时设SECURITY_ATTRIBUTES.bInheritHandle = TRUE,再用CreateProcess传入 - 调试时用
WinObj或handle.exe查看Section对象是否真存在、权限是否为0x1f0003(默认读写)
事情说清了就结束。真正卡住的点,往往在大小拆分、地址空间管理、落盘时机这三个地方,而不是 API 调用本身。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











