Подтвердить что ты не робот

Разница между `open` и` io.BytesIO` в двоичных потоках

Я изучаю работу с потоками в Python, и я заметил, что IO docs говорят следующее:

Самый простой способ создать двоичный поток - с open() с 'b' в строке режима:

f = open("myfile.jpg", "rb")

Бинарные потоки в памяти также доступны как объекты BytesIO:

f = io.BytesIO(b"some initial binary data: \x00\x01")

В чем разница между f, как определено open и f, как определено BytesIO. Другими словами, что делает "бинарный поток In-memory" и чем он отличается от того, что делает open?

4b9b3361

Ответ 1

Для простоты рассмотрим возможность записи вместо чтения на данный момент.

Итак, когда вы используете open(), например, скажите:

with open("test.dat", "wb") as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")

После выполнения будет создан файл с именем test.dat, содержащий Hello World. Данные не будут храниться в памяти после того, как они будут записаны в файл (если они не сохранены именем).

Теперь, когда вы считаете io.BytesIO():

with io.BytesIO() as f:
    f.write(b"Hello World")
    f.write(b"Hello World")
    f.write(b"Hello World")

который вместо того, чтобы записывать содержимое в файл, записывается в буфер памяти. Другими словами, кусок ОЗУ. По существу, следующая запись будет эквивалентна:

buffer = b""
buffer += b"Hello World"
buffer += b"Hello World"
buffer += b"Hello World"

В отношении примера с оператором with, тогда в конце также будет del buffer.

Основное отличие здесь - оптимизация и производительность. io.BytesIO способен выполнять некоторые оптимизации, что делает его быстрее, чем просто объединение всех b"Hello World" по очереди.

Просто, чтобы доказать это здесь небольшим эталоном:

  • Concat: 1.3529 секунд
  • BytesIO: 0.0090 секунд

import io
import time

begin = time.time()
buffer = b""
for i in range(0, 50000):
    buffer += b"Hello World"
end = time.time()
seconds = end - begin
print("Concat:", seconds)

begin = time.time()
buffer = io.BytesIO()
for i in range(0, 50000):
    buffer.write(b"Hello World")
end = time.time()
seconds = end - begin
print("BytesIO:", seconds)

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

Когда дело доходит до open("myfile.jpg", "rb"), который просто загружает и возвращает содержимое myfile.jpg. Где BytesIO снова просто буфер, содержащий некоторые данные.

Так как BytesIO - это просто буфер, если вы хотите позже записать содержимое в файл, вам нужно будет:

buffer = io.BytesIO()
# ...
with open("test.dat", "wb") as f:
    f.write(buffer.getvalue())

Кроме того, поскольку вы не упомянули о версии, я использую Python 3. Что касается примеров, просто я использую оператор with вместо вызова f.close()

Ответ 2

Использование open открывает файл на вашем жестком диске. В зависимости от того, какой режим вы используете, вы можете читать или записывать (или оба) с диска.

Объект A BytesIO не связан с каким-либо реальным файлом на диске. Это просто кусок памяти, который ведет себя как файл. Он имеет тот же API, что и файл-объект, возвращаемый с open (с режимом r+b, позволяющий читать и записывать двоичные данные).

BytesIO (и он закрывает sibling StringIO, который всегда находится в текстовом режиме) может быть полезен, когда вам нужно передавать данные в API или из него, которые ожидают получить файл-объект, но где вы предпочитаете для передачи данных напрямую. Вы можете загрузить свои входные данные в BytesIO, прежде чем передавать их в библиотеку. После его возврата вы можете получить любые данные, которые библиотека записала в файл из BytesIO, используя метод getvalue(). (Обычно вам нужно только сделать один из них, конечно.)

Ответ 3

f = open("myfile.jpg", "rb")

читать байты из файла с дискового диска и назначать такое значение объекту, на который ссылается "f", который хранится Python в памяти.

f = io.BytesIO(b"some initial binary data: \x00\x01")

присвоить значение байтового потока объекту, на который ссылается "f", который хранится Python в памяти.