Нарезка файла в Python

Я недавно работал над скриптами, которые берут файл, куски его и анализируют каждую часть. Поскольку позиции chunking зависят от содержимого, мне нужно прочитать его по одному байт за раз. Я не нуждаюсь в произвольном доступе, просто читая его линейно от начала до конца, выбирая определенные позиции, когда я иду, и уступаю содержимое фрагмента из предыдущей выбранной позиции в текущую.

Было очень удобно использовать файл с отображением памяти, обернутый bytearray. Вместо того, чтобы уступать кусок, я получаю смещение и размер куска, оставляя внешнюю функцию срезать его.

Это было также быстрее, чем накапливать текущий кусок в bytearray (и намного быстрее, чем накапливать в bytes!). Но у меня есть определенные опасения, которые я хотел бы затронуть:

  • Является ли копирование данных bytearray?
  • Я открываю файл как rb и mmap с помощью access=mmap.ACCESS_READ. Но bytearray является, в принципе, изменчивым контейнером. Это проблема производительности? Есть ли контейнер для чтения, который я должен использовать?
  • Поскольку я не накапливаю в буфере, я произвольно получаю доступ к bytearray (и, следовательно, к базовому файлу). Несмотря на то, что это может быть буферизировано, я боюсь, что будут проблемы в зависимости от размера файла и системной памяти. Это действительно проблема?

Ответ 1

  • Преобразование одного объекта в изменяемый объект приводит к копированию данных. Вы можете напрямую прочитать файл в bytearray, используя:

    f = open(FILENAME, 'rb')
    data = bytearray(os.path.getsize(FILENAME))
    f.readinto(data)
    

from http://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews#id12

  1. Существует строка для преобразования bytearray, поэтому есть потенциальная проблема с производительностью.

  2. bytearray - это массив, поэтому он может достигать предела PY_SSIZE_T_MAX/sizeof (PyObject *). Для получения дополнительной информации вы можете посетить Как большой может получить массив Python?

Ответ 2

Вы можете сделать этот маленький взлом.

import mmap

class memmap(mmap.mmap):
    def read_byte(self):
        return ord(super(memmap,self).read_byte())

Создайте класс, который наследует класс mmap и перезаписывает read_byte по умолчанию, который возвращает строку длиной от 1 до единицы, которая возвращает int. И тогда вы можете использовать этот класс как любой другой класс mmap.

Надеюсь, это поможет.