На этом шаге мы рассмотрим использование модуля mmap.
Вы хотите отобразить в память бинарный файл в форме изменяемого массива байтов - вероятно, для произвольного доступа к его содержимому или изменений прямо на месте.
Используйте модуль mmap для отображения файлов в память. Вот полезная функция, с помощью которой можно открыть файл и отобразить его в память переносимым способом:
>>> import os >>> import mmap >>> def memory_map(filename, access=mmap.ACCESS_WRITE): size = os.path.getsize(filename) fd = os.open(filename, os.O_RDWR) return mmap.mmap(fd, size, access=access) >>> size = 1000000 >>> with open('data', 'wb') as f: f.seek(size-1) f.write(b'\x00') 999999 1 >>>
А вот пример отображения содержимого в память с помощью функции memory_ map():
>>> m = memory_map('data') >>> len(m) 1000000 >>> m[0:10] b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' >>> m[0] 0 >>> # Переприсваивание среза >>> m[0:11] = b'Hello World' >>> m.close() >>> # Проверка того, что изменения были сделаны >>> with open('data', 'rb') as f: print(f.read(11)) b'Hello World' >>>
Объект mmap, возвращаемый функцией mmap(), может быть также использован в качестве менеджера контекста. В этом случае отображенный файл закрывается автоматически. Например:
>>> with memory_map('data') as m: print(len(m)) print(m[0:10]) 1000000 b'Hello Worl' >>> m.closed True >>>
По умолчанию показанная функция memory_map() открывает файл и на чтение, и на запись. Любые изменения данных копируются в исходный файл. Если требуется организовать доступ только для чтения, предоставьте mmap.ACCESSREAD в качестве аргумента access. Например:
m = memory_map(filename, mmap.ACCESS_READ)
Если вы намерены локально изменять данные, но не хотите, чтобы изменения записывались в исходный файл, используйте mmap.ACCESSCOPY:
m = memory_map(filename, mmap.ACCESS_COPY)
Использование mmap для отображения файлов в память может стать элегантным и эффективным решением для произвольного доступа к содержимому файла. Например, вместо открытия файла и выполнения различных комбинаций вызовов seek(), read() и write() вы просто отображаете файл и получаете доступ к любым данным через операции извлечения срезов.
Обычно память, выделяемая mmap(), выглядит как объект bytearray. Однако вы можете интерпретировать данные по-разному, используя функцию memoryview(). Например:
>>> m = memory_map('data') >>> # Представление памяти беззнаковых целых чисел >>> v = memoryview(m).cast('I') >>> v[0] = 7 >>> m[0:4] b'\x07\x00\x00\x00' >>> m[0:4] = b'\x07\x01\x00\x00' >>> v[0] 263 >>>
Стоит отметить, что отображение файла в память не вызывает чтения файла в память целиком. Он не копируется в некий буфер памяти или массив. Вместо этого операционная система выделяет участок виртуальной памяти под содержимое файла. По мере того как вы обращаетесь к различным участкам, эти куски файла будут читаться и отображаться в участок памяти по мере необходимости. Однако части файла, к которым никогда не производился доступ, останутся на диске.
Если не единственный интерпретатор Python отображает в память один и тот же файл, получившийся объект mmap может быть использован для обмена данными между интерпретаторами. Интерпретаторы могут читать и записывать данные одновременно, и изменения, которые были сделаны в одном интерпретаторе, автоматически будут доступны в других. Очевидно, что синхронизация требует дополнительного внимания, но этот подход иногда используется в качестве альтернативы передаче данных через каналы или сокеты.
Показанный выше рецепт написан максимально обобщенно, он работает и в Windows, и в Unix. Однако стоит отметить, что есть специфические для каждой платформы отличия в том, как "под капотом" работает mmap(). Также есть возможности по созданию анонимно отображенных участков памяти. Если вас это интересует, прочтите соответствующий раздел документации Python.
http://docs.python.org/3/library/mmap.html.
На следующем шаге мы рассмотрим манипулирование путями к файлам.