使用mmap映射大文件后重启程序读取全为0的问题排查
问题分析与解决
核心问题:fopen的打开模式错误
你使用"w+"模式打开文件,这个模式的行为是:
- 若文件已存在,会直接将其长度截断为0,彻底清空原有内容
- 若文件不存在,则创建新文件
所以第二次运行程序时,第一步就把之前写入数据的文件清空了,后续ftruncate只是把空文件扩展到指定大小,自然读取到的全是0。
修正方案
把fopen的模式改成"r+"(读写模式,文件必须存在,不会截断原有内容)。如果需要兼容文件不存在的场景,可以先判断文件是否存在,不存在时用"w+"创建,存在时用"r+"打开:
#include <sys/stat.h> #include <unistd.h> int64_t mmbytes = 1 << 36; FILE* file = nullptr; struct stat st; // 判断文件是否存在 if (stat(filename, &st) == 0) { // 文件存在,用r+模式打开(读写,不截断) file = fopen(filename, "r+"); } else { // 文件不存在,创建并打开 file = fopen(filename, "w+"); } if (!file) { perror("Failed: "); throw std::runtime_error(std::strerror(errno)); } int fd = fileno(file); // 仅当文件新创建或长度不符合要求时,执行ftruncate if (stat(filename, &st) != 0 || st.st_size != mmbytes) { int r = ftruncate(fd, mmbytes); if (r != 0) { perror("Failed: "); throw std::runtime_error(std::strerror(errno)); } } // 后续mmap代码保持不变 void* mm = mmap(nullptr, mmbytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mm == MAP_FAILED) { fprintf(stderr, "mmap error for output, errno %d\n", errno); exit(-1); }
额外注意事项
MAP_FILE标志在多数系统中是可选的(MAP_SHARED已隐含文件映射逻辑),可以移除,不影响功能- 操作完成后记得调用
munmap(mm, mmbytes)释放映射,fclose(file)关闭文件 - 64GB的大文件操作需确保系统支持(比如文件系统开启大文件特性、内存映射资源充足)
内容的提问来源于stack exchange,提问作者Kphysics
相关产品推荐
相关产品推荐

