因为open()+read()会将整个大文件一次性加载进内存,导致内存耗尽卡住;mmap仅建立虚拟映射、按需加载页,避免复制,适合随机访问和多进程共享,但顺序读一遍时传统迭代更轻量。

为什么直接用 open() 读大文件会卡住?
因为默认的 open() + read() 会把整个文件内容复制进 Python 的内存空间,不仅慢,还容易触发 MemoryError。而 mmap 不复制数据,只建立虚拟内存映射——操作系统按需从磁盘加载页,Python 看起来像在操作一个超大字节数组。
但注意:mmap 不是万能加速器。它适合随机访问、重复读、或只读场景;如果只是顺序读一遍,open().readline() 或 for line in file 反而更轻量。
mmap.mmap() 的关键参数怎么选?
最常踩坑的是 length 和 access 参数:
-
length:设为0表示映射整个文件(推荐),不要手动算os.path.getsize()再传进去——文件可能被其他进程截断,导致ValueError: mmap length is greater than file size -
access:只读场景必须用mmap.ACCESS_READ,别用默认的ACCESS_WRITE,否则会尝试写入文件末尾,可能触发PermissionError或静默失败 -
offset:对齐要求严格——必须是系统页大小(通常是 4096)的整数倍,否则抛ValueError: mmap offset is not a multiple of page size
正确写法:
立即学习“Python免费学习笔记(深入)”;
import mmap
with open("huge.log", "rb") as f:
with mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) as mm:
# 直接切片访问,比如前 100 字节
head = mm[:100]
如何安全地搜索字符串或解析行?
mmap 对象支持 .find()、.rfind()、.splitlines(),但行为和 bytes 略有差异:
-
.find(b"\n")没问题,但.find("\n")(str)会报TypeError——必须用bytes类型做匹配 -
.splitlines()返回的是list[bytes],不是list[str],解码要显式调用.decode("utf-8"),且需处理UnicodeDecodeError - 逐行遍历别用
for line in mm.splitlines()——这会一次性把所有行加载进内存;改用mm.find(b"\n", start)手动找换行符,配合切片提取
小技巧:用 mm[lo:hi].decode("utf-8", errors="ignore") 避免因局部乱码中断解析。
Windows 下 mmap 报 PermissionError: [Errno 13] 怎么办?
Windows 要求文件打开时明确声明共享模式,否则 mmap 会被拒绝:
- Python 3.8+:用
open(..., "rb", opener=lambda path, flags: os.open(path, flags | os.O_SEQUENTIAL))无用,真正有效的是加sharing参数(但标准open不支持) - 正确解法:改用
os.open()手动控制标志位
Windows 兼容写法:
import os
import mmap
<p>fd = os.open("data.bin", os.O_RDONLY)
try:
with mmap.mmap(fd, length=0, access=mmap.ACCESS_READ) as mm:
...
finally:
os.close(fd)
这个细节在 Linux/macOS 上不暴露,但一上 Windows 就崩——很多人卡在这里半天找不到原因。


















