io — потоки ввода/вывода¶
Этот модуль содержит дополнительные типы объектов stream (файлоподобных) и вспомогательные функции. Он предоставляет встроенную функцию open(), а также текстовые и двоичные буферы в памяти (StringIO, BytesIO), которые реализуют стандартный потоковый интерфейс read/write/seek.
Концептуальная иерархия¶
Отличие от CPython
Концептуальная иерархия базовых классов потоков в MicroPython упрощена, как описано в этом разделе.
(Абстрактные) базовые классы потоков, которые служат основой поведения всех конкретных классов, в CPython придерживаются нескольких дихотомий (попарных классификаций). В MicroPython они несколько упрощены и сделаны неявными для достижения более высокой эффективности и экономии ресурсов.
Важной дихотомией в CPython является различие между небуферизованными и буферизованными потоками. В MicroPython все потоки в настоящее время небуферизованы. Это связано с тем, что все современные ОС и даже многие ОСРВ и драйверы файловых систем уже выполняют буферизацию на своей стороне. Добавление ещё одного уровня буферизации контрпродуктивно (проблема, известная как «bufferbloat») и расходует драгоценную память. Обратите внимание, что всё же бывают случаи, когда буферизация может быть полезна, поэтому в дальнейшем мы можем добавить опциональную поддержку буферизации.
Но в CPython другая важная дихотомия связана с «буферизованностью» — это вопрос о том, может ли поток допускать короткие чтения/записи или нет. Короткое чтение — это когда пользователь запрашивает, например, 10 байт из потока, но получает меньше; аналогично для записи. В CPython небуферизованные потоки автоматически подвержены коротким операциям, тогда как буферизованные гарантируют отсутствие таковых. Отсутствие коротких чтений/записей — важное свойство, поскольку оно позволяет разрабатывать более лаконичные и эффективные программы — нечто весьма желательное для MicroPython. Поэтому, хотя MicroPython не поддерживает буферизованные потоки, он всё же обеспечивает потоки без коротких операций. Будут короткие операции или нет, зависит от потребностей каждого конкретного класса, но разработчикам настоятельно рекомендуется предпочитать поведение без коротких операций по причинам, изложенным выше. Например, сокеты MicroPython гарантированно избегают коротких чтений/записей. На самом деле в настоящее время в ядре нет ни одного примера класса потока с короткими операциями, и такой класс был бы специфичен для конкретного оборудования.
Поведение без коротких операций становится непростым в случае неблокирующих потоков, причём блокирующее и неблокирующее поведение — это ещё одна дихотомия CPython, полностью поддерживаемая MicroPython. Неблокирующие потоки никогда не ждут поступления или записи данных — они читают/записывают всё, что возможно, или сигнализируют об отсутствии данных (или возможности записать данные). Очевидно, что это конфликтует с политикой «без коротких операций», и действительно, случай неблокирующих буферизованных (и при этом без коротких операций) потоков запутан в CPython — в некоторых местах такое сочетание запрещено, в некоторых оно не определено или просто не документировано, а в некоторых случаях вызывает многословные исключения. В MicroPython дело обстоит гораздо проще: неблокирующие потоки важны для эффективных асинхронных операций, поэтому это свойство преобладает над свойством «без коротких операций». Так, блокирующие потоки будут по возможности избегать коротких чтений/записей (единственный случай короткого чтения — это достижение конца файла или ошибка (но ошибки не возвращают короткие данные, а вызывают исключения)), тогда как неблокирующие потоки могут возвращать короткие данные, чтобы избежать блокировки операции.
Последняя дихотомия — это двоичные и текстовые потоки. MicroPython, разумеется, поддерживает их, но если в CPython текстовые потоки по своей природе буферизованы, то в MicroPython это не так. (И это действительно один из случаев, для которых мы можем добавить поддержку буферизации.)
Обратите внимание, что в целях эффективности MicroPython не предоставляет абстрактных базовых классов, соответствующих приведённой выше иерархии, и реализовать или унаследовать класс потока на чистом Python невозможно.
Функции¶
Классы¶
- class io.IOBase¶
Базовый класс для объектов потока («файлоподобных»). Конкретные подклассы реализуют низкоуровневые методы ввода-вывода, приведённые ниже (
readinto,write,ioctl); среда выполнения строит на их основе более высокоуровневый потоковый протокол (read,readline,readlines,close, итерация), так что каждый экземпляр потока поддерживает эти методы, даже если подкласс их не определяет.Методы реализации (переопределяйте их в подклассе):
- readinto(buf: bytearray) int | None¶
Читает байты в доступный для записи буфер buf. Возвращает количество прочитанных байтов,
0в конце потока илиNone, если данных в данный момент нет (для неблокирующего потока).
- write(buf: bytes) int | None¶
Записывает байты из buf. Возвращает количество записанных байтов или
None, если запись в данный момент не может быть выполнена (для неблокирующего потока).
- ioctl(request: int, arg: int) int¶
Управляет нижележащим потоком/устройством. request — один из кодов запроса
MP_STREAM_*. Возвращает неотрицательное значение при успехе или отрицательное значениеerrnoпри ошибке.
Методы потокового протокола (доступны для каждого экземпляра потока):
- read(size: int = -1)¶
Читает и возвращает до size байтов (или символов в текстовом режиме). Если size опущен или отрицателен, читает до конца потока. Возвращает
bytesдля двоичных потоков иstrдля текстовых потоков; пустой результат означает конец потока.
- readline(size: int = -1)¶
Читает и возвращает одну строку, включая завершающий символ новой строки, если он присутствует. Если задан size, читается не более size байтов (или символов). Возвращает пустые
bytes/strв конце потока.
- readlines() list¶
Читает до конца потока и возвращает
listстрок, каждая с её завершающим символом новой строки.
- close() None¶
Закрывает поток и освобождает все нижележащие ресурсы. Операции над закрытым потоком вызывают
OSError(илиValueErrorдля потоков в памяти).
- seek(offset: int, whence: int = 0) int¶
Изменяет текущую позицию в потоке на offset байтов относительно whence (
0= начало потока,1= текущая позиция,2= конец потока). Возвращает новую абсолютную позицию. ВызываетOSErrorдля потока, не поддерживающего перемещение.
- flush() None¶
Сбрасывает все буферы записи, отправляя ожидающие данные на нижележащее устройство или в файл. Не выполняет никаких действий для потоков, не использующих буферизацию.
Прямая итерация потока выдаёт по одной строке за итерацию — эквивалентно вызову
readline()в цикле до возврата признака конца потока в виде пустой строки. Поток также поддерживает протокол менеджера контекста, так чтоwith open(...) as f:закрывает поток автоматически.Примечание
Модуль потоков MicroPython также предоставляет C-помощники с суффиксом «1»
mp_stream_read1_obj,mp_stream_readinto1_objиmp_stream_write1_obj, которые выполняют один нижележащий вызов ввода-вывода вместо цикла до полного удовлетворения запроса. Они используются внутренне такими классами, какmachine.UART, для реализации собственныхread/write— но ни один стандартный класс потока не привязывает их в качестве вызываемых из Python методовread1/readinto1/write1.
- class io.StringIO(string: str = '')¶
Файлоподобный объект в памяти для ввода/вывода в текстовом режиме (аналогично обычному файлу, открытому с модификатором «t»). Начальное содержимое можно задать параметром string (который должен быть обычной строкой). Экземпляры также поддерживают протокол менеджера контекста (можно использовать в инструкции
with).- read(size: int = -1) str¶
Читает и возвращает до size символов. Если size опущен или отрицателен, читает и возвращает всё оставшееся содержимое.
- readline(size: int = -1) str¶
Читает и возвращает одну строку. Если задан size, читается не более size символов.
- readinto(buf: bytearray) int¶
Читает в предварительно выделенный доступный для записи буфер buf и возвращает количество прочитанных байтов.
- seek(offset: int, whence: int = 0) int¶
Изменяет позицию в потоке на offset относительно whence (
0= начало,1= текущая,2= конец) и возвращает новую абсолютную позицию.
- close() None¶
Закрывает поток и освобождает нижележащий буфер. Дальнейшие операции над закрытым потоком вызывают
ValueError.
- class io.StringIO(alloc_size: int)
Создаёт пустой объект
StringIO, заранее выделенный для хранения до alloc_size байтов, так что запись до этого количества байтов не приведёт к перевыделению буфера (избегая ситуации нехватки памяти или её фрагментации). Этот конструктор является расширением MicroPython, рекомендуемым только для особых случаев и системных библиотек, но не для пользовательских приложений.Отличие от CPython
Этот конструктор является расширением MicroPython.
- read(size: int = -1) str
Читает и возвращает до size символов. Если size опущен или отрицателен, читает и возвращает всё оставшееся содержимое.
- readline(size: int = -1) str
Читает и возвращает одну строку. Если задан size, читается не более size символов.
- readinto(buf: bytearray) int
Читает в предварительно выделенный доступный для записи буфер buf и возвращает количество прочитанных байтов.
- seek(offset: int, whence: int = 0) int
Изменяет позицию в потоке на offset относительно whence (
0= начало,1= текущая,2= конец) и возвращает новую абсолютную позицию.
- tell() int
Возвращает текущую позицию в потоке.
- flush() None
Сбрасывает буферы записи. Для потока в памяти не выполняет никаких действий.
- close() None
Закрывает поток и освобождает нижележащий буфер. Дальнейшие операции над закрытым потоком вызывают
ValueError.
- getvalue() str
Возвращает текущее содержимое нижележащего буфера.
- class io.BytesIO(string: bytes = b'')¶
Файлоподобный объект в памяти для ввода/вывода в двоичном режиме (аналогично обычному файлу, открытому с модификатором «b»). Начальное содержимое можно задать параметром string (который должен быть объектом bytes). Экземпляры также поддерживают протокол менеджера контекста (можно использовать в инструкции
with).- read(size: int = -1) bytes¶
Читает и возвращает до size байтов. Если size опущен или отрицателен, читает и возвращает всё оставшееся содержимое.
- readline(size: int = -1) bytes¶
Читает и возвращает одну строку. Если задан size, читается не более size байтов.
- readinto(buf: bytearray) int¶
Читает в предварительно выделенный доступный для записи буфер buf и возвращает количество прочитанных байтов.
- seek(offset: int, whence: int = 0) int¶
Изменяет позицию в потоке на offset относительно whence (
0= начало,1= текущая,2= конец) и возвращает новую абсолютную позицию.
- close() None¶
Закрывает поток и освобождает нижележащий буфер. Дальнейшие операции над закрытым потоком вызывают
ValueError.
- class io.BytesIO(alloc_size: int)
Создаёт пустой объект
BytesIO, заранее выделенный для хранения до alloc_size байтов, так что запись до этого количества байтов не приведёт к перевыделению буфера (избегая ситуации нехватки памяти или её фрагментации). Этот конструктор является расширением MicroPython, рекомендуемым только для особых случаев и системных библиотек, но не для пользовательских приложений.Отличие от CPython
Этот конструктор является расширением MicroPython.
- read(size: int = -1) bytes
Читает и возвращает до size байтов. Если size опущен или отрицателен, читает и возвращает всё оставшееся содержимое.
- readline(size: int = -1) bytes
Читает и возвращает одну строку. Если задан size, читается не более size байтов.
- readinto(buf: bytearray) int
Читает в предварительно выделенный доступный для записи буфер buf и возвращает количество прочитанных байтов.
- seek(offset: int, whence: int = 0) int
Изменяет позицию в потоке на offset относительно whence (
0= начало,1= текущая,2= конец) и возвращает новую абсолютную позицию.
- tell() int
Возвращает текущую позицию в потоке.
- flush() None
Сбрасывает буферы записи. Для потока в памяти не выполняет никаких действий.
- close() None
Закрывает поток и освобождает нижележащий буфер. Дальнейшие операции над закрытым потоком вызывают
ValueError.
- getvalue() bytes
Возвращает текущее содержимое нижележащего буфера.