Предпочитаете BytesIO или байты для внутреннего интерфейса в Python?

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

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

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

Каковы различные компромиссы между использованием BytesIO и bytes?

def put_file(location, contents_as_bytes):
def put_file(location, contents_as_fp):
def get_file_contents(location):
def get_file_contents(location, fp):

Поэкспериментировав, я обнаружил, что использование файловых интерфейсов (BytesIO и т. д.) требует некоторых административных издержек с точки зрения seek(0) и т. д. Это вызывает такие вопросы, как:

  • лучше seek до того, как вы начнете, или после того, как закончите?
  • вы seek к началу или просто работаете с позиции, в которой находится файл?
  • вы должны tell() сохранить позицию?
  • глядя на что-то вроде shutil.copyfileobj, он не ищет

Одно преимущество, которое я обнаружил при использовании файловых интерфейсов, заключается в том, что он позволяет передавать fp для записи, когда вы извлекаете данные. Что, кажется, дает хорошую гибкость.

def get_file_contents(location, write_into=None):
    if not write_into:
        write_into = io.BytesIO()

    # get the contents and put it into write_into

    return write_into

get_file_contents('blah', file_on_disk)
get_file_contents('blah', gzip_file)
get_file_contents('blah', temp_file)
get_file_contents('blah', bytes_io)
new_bytes_io = get_file_contents('blah')
# etc

Есть ли веская причина предпочесть BytesIO просто использованию фиксированных байтов при разработке интерфейса в python?


person Aidan Kane    schedule 18.02.2015    source источник


Ответы (1)


Преимущество объектов io.BytesIO заключается в том, что они реализуют общий интерфейс (широко известный как «файлоподобный» объект). Объекты BytesIO имеют внутренний указатель (позиция которого возвращается функцией tell()), и при каждом вызове read(n) указатель смещается на n байт. Бывший.

import io

buf = io.BytesIO(b'Hello world!')
buf.read(1) # Returns b'H'

buf.tell()  # Returns 1
buf.read(1) # Returns b'e'

buf.tell() # Returns 2

# Set the pointer to 0.
buf.seek(0)
buf.read() # This will return b'H', like the first call.

В вашем случае использования как объект bytes, так и объект io.BytesIO, возможно, не лучшие решения. Они будут считывать полное содержимое ваших файлов в память.

Вместо этого вы можете посмотреть tempfile.TemporaryFile (https://docs.python.org/3/library/tempfile.html).

person Cochise Ruhulessin    schedule 25.02.2015
comment
Спасибо за отзыв. В итоге я использовал комбинацию байтов и файловых объектов. Хорошая мысль о tempfile — использование файловоподобных объектов дает гибкость использования tempfile там, где это необходимо, что может дать лучший компромисс между временем и пространством для некоторых случаев использования. - person Aidan Kane; 27.02.2015
comment
Последний buf.read() вернет всю строку. Если вы опустите аргумент size или используете отрицательное значение, он будет считываться до EOF. Я думаю, вы имели в виду buf.read(1). - person Caleb Fenton; 01.06.2019