
使用python的`mmap`模块时,若传入的`offset`参数不是系统内存分配粒度(`mmap.allocationgranularity`)的整数倍,或超出文件实际大小,将触发`oserror: [errno 22] invalid argument`错误。
mmap并非任意偏移均可映射——它底层依赖操作系统的内存映射机制,而操作系统要求映射起始地址(即offset)必须对齐到特定边界,该边界由mmap.ALLOCATIONGRANULARITY定义(在大多数现代Linux/macOS系统上为4096字节,Windows通常也为4096,但可能因架构略有差异)。即使文件本身支持字节级寻址,mmap的offset也必须是该粒度的整数倍;否则内核直接拒绝映射请求,抛出“Invalid argument”。
此外,offset还须满足:offset + length ≤ 文件大小(当length=0时,表示映射从offset到文件末尾,因此要求offset ≤ 文件大小)。若offset越界,同样会报错。
✅ 正确用法示例:
import mmap
import os
import sys
if len(sys.argv) != 3:
print("Usage: python script.py ")
sys.exit(1)
filepath = sys.argv[1]
offset = int(sys.argv[2])
# 获取文件大小与对齐粒度
with open(filepath, 'rb') as f:
file_size = os.fstat(f.fileno()).st_size
granularity = mmap.ALLOCATIONGRANULARITY
# 校验 offset 对齐性与范围
if offset % granularity != 0:
raise ValueError(f"offset {offset} is not a multiple of ALLOCATIONGRANULARITY ({granularity})")
if offset > file_size:
raise ValueError(f"offset {offset} exceeds file size {file_size}")
# 安全打开并映射
with open(filepath, 'rb') as f:
mm = mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ, offset=offset)
print(f"Successfully mapped {len(mm)} bytes starting at offset {offset}")
# 示例:读取前16字节
print("First 16 bytes:", mm[:16].hex() if len(mm) >= 16 else mm[:].hex()) ⚠️ 注意事项:
立即学习“Python免费学习笔记(深入)”;
- 始终使用with open(...)确保文件句柄安全管理(尤其在只读模式下,避免mmap生命周期长于文件对象);
- length=0虽便捷,但隐式依赖文件大小,务必先校验offset有效性;
- 不同平台ALLOCATIONGRANULARITY值可能不同,切勿硬编码为4096,应始终通过mmap.ALLOCATIONGRANULARITY获取;
- 若需按非对齐偏移读取数据(如解析二进制协议),应在mmap对齐映射后,再用切片或struct.unpack_from等进行逻辑偏移访问,而非强行传入非法offset。
总结:mmap的offset是系统级约束参数,不是普通文件偏移。坚持“先对齐、再校界、后映射”三步原则,可彻底规避Invalid argument错误。










