Модуль `io` в Python
В этой статье объясняется модуль io в Python.
Мы объясним модуль io в Python с практическими примерами.
YouTube Video
Модуль io в Python
Обработка ввода/вывода составляет основу всех видов работы с данными, таких как файлы, сети и стандартный ввод/вывод. Модуль io в Python предоставляет набор абстрактных классов, объединяющих эти операции ввода/вывода. Ключевое понятие для понимания этого модуля — это идея «потока».
Что такое поток?
Поток — это абстрактный поток для последовательного и непрерывного чтения и записи данных.
При чтении содержимого файла по байтам или при передаче и получении данных по сети все это может рассматриваться как потоки данных.
Благодаря абстрагированию этого механизма, файлы, память и сети — различные источники ввода/вывода — могут обрабатываться с помощью общих операций, таких как чтение и запись.
Модуль io в Python предоставляет унифицированный интерфейс для потоков, что позволяет эффективно работать как с текстовыми, так и с бинарными данными.
Базовая структура модуля io
Модуль io имеет трёхуровневую иерархию в зависимости от типа потоков.
-
Низкоуровневый слой (
RawIOBase)RawIOBaseобрабатывает самый низкоуровневый байтовый ввод/вывод, такой как файловые дескрипторы ОС и устройства. -
Буферизованный слой (
BufferedIOBase)BufferedIOBaseпредоставляет кэш (буфер) для повышения эффективности ввода/вывода.BufferedReaderиBufferedWriter— типичные примеры. -
Текстовый слой (
TextIOBase)TextIOBaseпреобразует последовательности байтов в строки и управляет кодировкой. Обычно при открытии файла функциейopen()используетсяTextIOWrapperиз этого слоя.
Благодаря этой структуре, модуль io чётко разделяет текстовый и бинарный ввод/вывод, позволяя гибко их комбинировать.
Базовая структура модуля io
RawIOBase работает с файловыми дескрипторами ОС на самом нижнем уровне, затем BufferedIOBase добавляет буферизацию, а верхний слой TextIOBase занимается преобразованием строк.
1import io
2
3# Check the core base classes hierarchy
4print(io.IOBase.__subclasses__())- Этот код проверяет группу абстрактных классов, наследуемых от
IOBase. Вы можете увидетьTextIOBase,BufferedIOBaseиRawIOBase, что подтверждает иерархическую структуру.
io.IOBase: Базовый класс для всех
IOBase — это абстрактный базовый класс для всех объектов ввода/вывода, определяющий общие методы, такие как close(), flush() и seekable(). Он редко используется напрямую и обычно применяется через производные классы.
1import io
2
3f = io.StringIO("data")
4print(f.seekable()) # True
5print(f.readable()) # True
6print(f.writable()) # True
7f.close()- Этот пример показывает, что общие методы
IOBaseтакже могут использоваться в производных классах.seekable()иreadable()полезны для проверки свойств потока.
io.RawIOBase: Самый низкоуровневый слой
RawIOBase — это слой, ближайший к файловому дескриптору ОС и не выполняющий буферизацию. Типичная реализация — FileIO, который читает и записывает по байтам.
1import io, os
2
3# Create a low-level FileIO object (no buffering)
4fd = os.open('raw_demo.bin', os.O_RDWR | os.O_CREAT)
5raw = io.FileIO(fd, mode='w+')
6raw.write(b'abc123')
7raw.seek(0)
8print(raw.read(6)) # b'abc123'
9raw.close()FileIO— конкретная реализацияRawIOBase; все операции чтения и записи выполняются как объектbytes. Эффективность может быть повышена при объединении с верхним слоемBufferedIOBase.
io.BufferedIOBase: Промежуточный слой (с буферизацией)
BufferedIOBase — это промежуточный слой, который выполняет буферизацию, делая доступ к диску более эффективным. Основные реализации — это BufferedReader, BufferedWriter, BufferedRandom и BufferedRWPair.
1import io
2
3# Create a buffered binary stream on top of a BytesIO (simulate file)
4base = io.BytesIO()
5buffered = io.BufferedWriter(base)
6buffered.write(b'Python IO buffering')
7buffered.flush()
8base.seek(0)
9print(base.read()) # b'Python IO buffering'- В этом примере данные, записанные через
BufferedWriter, временно сохраняются в буфере памяти и фактически передаются на нижний уровень после вызоваflush().
Пример BufferedReader
BufferedReader — это поток с буферизацией только для чтения, который поддерживает эффективное чтение с помощью методов peek() и read().
1import io
2
3stream = io.BytesIO(b"1234567890")
4reader = io.BufferedReader(stream)
5print(reader.peek(5)) # b'12345' (non-destructive)
6print(reader.read(4)) # b'1234'
7print(reader.read(3)) # b'567'peek()только «подсматривает» данные и не перемещает указатель. Комбинируя его с методомread(), вы можете гибко управлять буферизацией.
io.TextIOBase: Слой только для текста
TextIOBase — это уровень абстракции для работы со строками, который внутренне выполняет декодирование и кодирование. Типичный класс-реализация — это TextIOWrapper.
1import io
2
3# Wrap a binary stream to handle text encoding
4binary = io.BytesIO()
5text_stream = io.TextIOWrapper(binary, encoding='utf-8')
6text_stream.write("\u3053\u3093\u306B\u3061\u306F")
7text_stream.flush()
8
9# Reset stream position
10binary.seek(0)
11
12# Read bytes once
13data = binary.read()
14
15# Show both raw bytes and decoded text
16print("Raw bytes:", data)
17print("Decoded text:", data.decode('utf-8'))- В этом примере
TextIOWrapperкодирует строку в UTF-8 и записывает её во внутренний бинарный поток.
Пример чтения с использованием TextIOWrapper
Декодирование производится автоматически при чтении.
1import io
2
3binary_data = io.BytesIO("Python I/O".encode('utf-8'))
4text_reader = io.TextIOWrapper(binary_data, encoding='utf-8')
5print(text_reader.read()) # 'Python I/O'TextIOWrapperслужит базовым классом для текстового ввода/вывода и является основой почти для всех операций с файлами на высоком уровне.
io.StringIO: Текстовый поток в памяти
StringIO — это класс, позволяющий работать со строками в памяти как с файлами. Он полезен для тестирования ввода/вывода и временного создания данных.
1import io
2
3text_buf = io.StringIO()
4text_buf.write("In-memory text stream")
5text_buf.seek(0)
6print(text_buf.read()) # 'In-memory text stream'StringIOпозволяет выполнять файловые операции без использования диска и широко используется в юнит-тестах.
io.BytesIO: Бинарный поток в памяти
BytesIO — это файловый класс в памяти для работы с последовательностями байтов (bytes). Он полезен для случаев, таких как обработка бинарных данных или сжатие данных, когда вы не хотите использовать файлы.
1import io
2
3buf = io.BytesIO()
4buf.write(b'\x01\x02\x03')
5buf.seek(0)
6print(list(buf.read())) # [1, 2, 3]BytesIOимеет тот же интерфейс, что иBufferedIOBase, и может использоваться как замена для многих файловых API.
Пользовательские потоки (создание собственных классов)
Классы в модуле io расширяемы, что позволяет создавать собственные классы потоков. Ниже приведён пример подкласса TextIOBase, который делает все символы заглавными при записи.
1import io
2
3class UpperTextIO(io.TextIOBase):
4 def __init__(self):
5 self.buffer = ""
6 def write(self, s):
7 self.buffer += s.upper()
8 return len(s)
9
10u = UpperTextIO()
11u.write("hello io")
12print(u.buffer) # "HELLO IO"- Пока вы соблюдаете контракт
TextIOBase, вы можете определять любое подобное поведение. Также легко расширять потоки для конкретных целей, например работы с файлами и сетями.
Резюме
Модуль io организует обработку ввода/вывода в иерархию абстрактных и конкретных классов.
RawIOBase— это класс для байтового ввода/вывода на уровне ОС.BufferedIOBase— это класс, обеспечивающий эффективный слой кэширования.TextIOBase— это класс, управляющий чтением и записью строк.StringIOиBytesIO— это классы, предоставляющие потоки в памяти.
Понимание этих классов позволяет точно понимать работу системы ввода/вывода Python и применять их для файловых операций, сетевого взаимодействия и проектирования тестовых потоков.
Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.