mmap 是原始文件访问;它从f (从gzip.open 创建的对象)唯一使用的是.fileno() 方法,它获取原始文件描述符,它根本不知道文件被压缩(gzip.open 包装了原始文件层中的文件描述符按需执行解压缩,但低级文件描述符不知道所有这些)。
为了解决一些困惑:mmap 不会为您带来神奇的 I/O 性能提升。如果您满足以下条件,这将非常有用:
- 正在对文件执行随机访问,理想情况下
- 重复读取文件(经常重新访问您之前访问过的相同页面)
对于像 JSON 这样的东西,随机访问本质上是无用的;该文件可能是 UTF-8 文本,因此随机访问甚至不能保证落在有效字符的开头,即使是,JSON 中字符 N 的解释取决于字符 0 到 N- 的解释1(我们是在一个对象、一个数组、一个字符串等吗?不知道其余的就不能知道)。所以#1 不适用。
同样,一遍又一遍地重复读取同一个 JSON 文件并没有什么好处;反序列化一次并使用它。
重点是,跳过mmap,然后做:
import json
import gzip
with gzip.open("/home/test.json.gz", mode="r") as f:
data = json.load(f)
如果您的文件格式适合随机访问,您仍然不能直接使用 gzip 压缩文件(压缩数据,如 JSON,取决于上下文;您需要前一个字节的上下文来解释下一个字节)。如果您出于某种原因必须使用mmap,则需要先对其进行解压缩,例如:
import gzip
import shutil
import tempfile
with tempfile.TemporaryFile() as f_temp: # Make an unnamed temporary file to use for mmap
with gzip.open("/home/test.data.gz") as f:
shutil.copyfileobj(f, f_temp) # Efficiently decompress from gzip to temp file
f_temp.flush() # Ensure no data stuck in user-mode buffers
# Memory map temporary file and use it
with mmap.mmap(f_temp.fileno(), length=0, access=mmap.ACCESS_READ) as f_mmap:
print(f_mmap.read())
# mapping closed and deleted outside its with
# temporary file closed and deleted outside its with
在实践中,如果您要经常重复使用此文件,我建议您将其未压缩存储,以避免每次在使用前解压缩,但我想我会演示如何制作这样的文件以防万一您的实际用例需要它。