[Изменить: эта проблема относится только к 32-разрядным системам. Если ваш компьютер, ваша ОС и ваша реализация python являются 64-битными, то mmap-ing огромные файлы работают надежно и чрезвычайно эффективны.]
Я пишу модуль, который, среди прочего, позволяет побитовое чтение доступа к файлам. Файлы потенциально могут быть большими (сотни ГБ), поэтому я написал простой класс, который позволяет обрабатывать файл как строку и скрывает все поиски и чтение.
В то время, когда я написал класс оболочки, я не знал о mmap module. При чтении документации для mmap я подумал "отлично - это то, что мне нужно, я вытащу свой код и заменим его на mmap. Это, вероятно, намного эффективнее и всегда полезно удалять код".
Проблема в том, что mmap не работает для больших файлов! Это очень удивительно для меня, поскольку я думал, что это, пожалуй, самое очевидное приложение. Если файл превышает несколько гигабайт, я получаю EnvironmentError: [Errno 12] Cannot allocate memory
. Это происходит только с 32-битной сборкой Python, поэтому, похоже, она исчерпывает адресное пространство, но я не могу найти документацию по этому вопросу.
Мой код просто
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]
за исключением того, что нет ограничений на размер файла. Не очень сложно на самом деле...