内存映射(mmap/mapviewoffile)比fread快2–5倍,但需满足随机访问、少修改、容忍缺页延迟;小文件或未优化io设置时反而更慢;须注意页对齐、跨平台释放差异及返回值校验。

内存映射比 fread 快,但不是所有场景都适用
直接用 mmap(Linux/macOS)或 CreateFileMapping(Windows)读大文件,本质是让内核把文件页“挂”进进程虚拟地址空间,避免用户态缓冲区拷贝。但前提是文件可随机访问、不频繁修改、且你愿意承担页面错误带来的延迟抖动。
- 只读场景下,
mmap+ 指针偏移访问通常比循环fread快 2–5 倍;写入时若用MAP_SHARED,脏页回写由内核异步完成,但崩溃可能丢数据 - 小文件(mmap 启动开销反而更高;
fread配合 64KB–1MB 缓冲区更稳 - Windows 上
CreateFileMapping要求先用CreateFile打开文件,且dwMaximumSizeHigh/Low必须精确——传 0 会失败,得用GetFileSize先查大小
分块读写必须自己控制缓冲区边界
用 fread/fwrite 处理 GB 级文件时,系统默认 libc 缓冲(如 8KB)完全不够看,频繁 syscall 是性能杀手。关键不是“要不要分块”,而是“块大小和对齐怎么定”。
- 推荐块大小设为 1MB(
1024 * 1024),既避开大多数文件系统块大小(4KB/64KB),又适配 CPU cache line 和 TLB 容量 - 读取时务必检查
fread返回值:它可能少于请求字节数(EOF 或磁盘错误),不能假设“调用一次就读满” - 写入前用
fseek定位时,若文件未提前ftruncate到目标长度,空洞区域在 Linux 上会填 0,在 Windows 上可能报错Invalid argument
std::ifstream 在大文件上默认很慢,必须关同步
C++ 标准库流默认与 C stdio 同步(std::ios_base::sync_with_stdio(true)),每次 operator>> 都要锁 stdin/stdout,GB 文件可能慢 10 倍以上。
- 开头加一句
std::ios_base::sync_with_stdio(false),再禁用cin.tie(nullptr),能逼近fread性能 - 但
std::ifstream::read仍走 libc 缓冲,别用getline或格式化输入(>>)解析二进制数据——它会逐字节扫描换行符,O(n) 变成 O(n²) - 若需按行处理文本大文件,改用
fgets+ 自己管理缓冲区,或用mmap后strchr扫描,别信std::getline的“简洁”
跨平台 mmap 封装要注意页对齐和错误码
Linux 的 mmap 要求 offset 是页大小(getpagesize())整数倍;Windows 的 MapViewOfFile 要求 offset 是 64KB 对齐。硬写死 4096 会崩在 Windows 上。
立即学习“C++免费学习笔记(深入)”;
- Linux 下用
sysconf(_SC_PAGESIZE)获取真实页大小;Windows 下用GetSystemInfo(&si); si.dwAllocationGranularity(通常是 64KB) -
mmap失败返回MAP_FAILED(即(void*)-1),不是nullptr;Windows 下MapViewOfFile失败才返回nullptr - 释放时,Linux 用
munmap,Windows 用UnmapViewOfFile+CloseHandle(两次调用),漏掉任意一个都会泄漏句柄或内存
真正卡住人的从来不是“选 mmap 还是 fread”,而是 mmap 的 offset 对齐、Windows 句柄生命周期、以及 fread 返回值校验——这些点错一个,程序就静默出错或内存暴涨。









