[编辑:此问题仅适用于32位系统。 如果您的计算机,操作系统和python实现是64位的,则映射大型文件将可靠且非常有效。]
我正在编写一个模块,该模块除其他功能外,还允许对文件进行按位读取访问。这些文件可能很大(数百GB),因此我编写了一个简单的类,使我可以像对待字符串一样对待文件,并隐藏所有查找和读取内容。
当时我写了包装类,我对mmap模块一无所知。在阅读mmap的文档时,我认为 “很棒-这就是我所需要的,我将取出我的代码,并用mmap替换它。它可能更有效,并且删除代码总是很好。”
问题是mmap不适用于大文件!这让我感到非常惊讶,因为我认为这可能是最明显的应用。如果文件超过几GB,则得到一个EnvironmentError:[Errno 12] Cannot allocate memory。这仅在32位Python构建中发生,因此似乎地址空间不足,但是我找不到任何文档。
EnvironmentError:[Errno 12] Cannot allocate memory
我的代码是
f = open('somelargefile', 'rb') map = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
所以我的问题是 我是否在这里缺少明显的东西? 是否有办法使mmap在大型文件上可移植地工作,还是我应该回到朴素的文件包装器?
更新:似乎有一种感觉,Python mmap应该具有与POSIX mmap相同的限制。为了更好地表达我的不满,这里有一个简单的类,其中包含mmap功能的一小部分。
import os class Mmap(object): def __init__(self, f): """Initialise with a file object.""" self.source = f def __getitem__(self, key): try: # A slice self.source.seek(key.start, os.SEEK_SET) return self.source.read(key.stop - key.start) except AttributeError: # single element self.source.seek(key, os.SEEK_SET) return self.source.read(1)
它是只读的,没有任何花哨的内容,但是我可以做到与mmap相同:
map2 = Mmap(f) print map2[0:10] print map2[10000000000:10000000010]
除了文件大小没有限制。真的不太难…
从IEEE 1003.1:
mmap()函数应在进程的地址空间与文件,共享内存对象或[TYM]类型的内存对象之间建立映射。
它需要所有的虚拟地址空间,因为这正是这样mmap() 做的 。
mmap()
这是不是事实 真正 的内存不多了并不重要-你不能映射比你有更多的可用地址空间。由于您然后将结果当作存储器一样 进行 访问和访问,因此您建议如何精确地将2 ^ 32多个字节访问到文件中?即使mmap()没有失败,您仍然只能读取前4GB,然后再用尽32位地址空间中的空间。当然,您可以mmap()在文件上滑动32位窗口,但这并不一定会为您带来任何好处,除非您可以优化访问方式以限制访问前一个窗口的次数。