os.read () дает OSError: [Errno 22] Недопустимый аргумент при чтении больших данных

1

Я использую следующий метод для чтения двоичных данных из любого заданного смещения в двоичном файле. Двоичный файл у меня есть огромный 10GB, так что я обычно читаю ее часть, когда это необходимо, указав, из которых компенсировано я должен start_read и сколько байт для чтения num_to_read. Я использую Python 3.6.4 :: Anaconda, Inc., платформу Darwin-17.6.0-x86_64-i386-64bit и os- модуль:

def read_from_disk(path, start_read, num_to_read, dim):
    fd = os.open(path, os.O_RDONLY)
    os.lseek(fd, start_read, 0)  # Where to (start_read) from the beginning 0
    raw_data = os.read(fd, num_to_read)  # How many bytes to read
    C = np.frombuffer(raw_data, dtype=np.int64).reshape(-1, dim).astype(np.int8)
    os.close(fd)
    return C

Этот метод работает очень хорошо, когда кусок данных для чтения составляет менее 2 ГБ. Когда num_to_read > 2GG, я получаю эту ошибку:

raw_data = os.read(fd, num_to_read)  # How many to read (num_to_read)
OSError: [Errno 22] Invalid argument

Я не уверен, почему возникает эта проблема и как ее исправить. Любая помощь высоко ценится.

Теги:
python-3.x
operating-system

1 ответ

4
Лучший ответ

Функция os.read - это всего лишь тонкая оболочка вокруг функции read платформы.

На некоторых платформах это неподписанный или подписанный 32-битный int, 1, что означает, что наибольшее число, которое вы можете read за один проход на этих платформах, составляет соответственно 4 ГБ или 2 ГБ.

Итак, если вы хотите больше читать, и вы хотите быть кросс-платформенным, вам нужно написать код для обработки этого и буферизовать несколько файлов read.

Это может быть немного больно, но вы намеренно используете функцию прямого сопоставления непосредственно для отображения в OS-API. Если вам это не нравится:

  • Используйте объекты io модуля (Python 3.x) или объекты file (2.7), которые вы вернетесь из open.
  • Просто дайте NumPy прочитать файлы, которые будут иметь дополнительное преимущество в том, что NumPy достаточно умен, чтобы не пытаться сначала прочитать все это в памяти.
  • Или, для больших файлов, вы можете пойти на более низкий уровень и использовать mmap (если вы на 64-битной платформе).

Правильная вещь здесь - это почти наверняка сочетание первых двух. В Python 3 это будет выглядеть так:

with open(path, 'rb', buffering=0) as f:
    f.seek(start_read)
    count = num_to_read // 8 # how many int64s to read
    return np.fromfile(f, dtype=np.int64, count=count).reshape(-1, dim).astype(np.int8)

1. Для Windows, функция _read библиотеки _read -эмуляции использует int для аргумента count, который подписан 32-битным.Для любой другой современной платформы, см POSIX read, а затем посмотреть определения size_t, ssize_t и off_t, на вашей платформе.Обратите внимание, что на многих платформах POSIX есть отдельные 64-битные типы и соответствующие функции вместо изменения значения существующих типов на 64-разрядные.Python будет использовать стандартные типы, а не специальные 64-битные типы.

  • 0
    Большое спасибо. Я ценю ваш четкий ответ. Как я могу указать num_to_read в вашем коде? Это очень важно для меня, так как я не хочу читать весь файл, только его часть

Ещё вопросы

Сообщество Overcoder
Наверх
Меню