io — потоки введення/виведення¶
Цей модуль містить додаткові типи об’єктів stream (файлоподібних) та допоміжні функції. Він надає вбудовану функцію open(), а також буфери тексту та двійкових даних у пам’яті (StringIO, BytesIO), що реалізують стандартний інтерфейс потоку read/write/seek.
Концептуальна ієрархія¶
Відмінність від CPython
Концептуальна ієрархія базових класів потоків спрощена в MicroPython, як описано в цьому розділі.
Абстрактні базові класи потоків, які служать основою для поведінки всіх конкретних класів, дотримуються кількох дихотомій (попарних класифікацій) у CPython. У MicroPython вони дещо спрощені та зроблені неявними для підвищення ефективності та економії ресурсів.
Важлива дихотомія в CPython — буферизовані та небуферизовані потоки. У MicroPython усі потоки наразі небуферизовані. Це пов’язано з тим, що всі сучасні ОС, і навіть багато RTOS та драйверів файлової системи вже виконують буферизацію на своєму боці. Додавання ще одного рівня буферизації є контрпродуктивним (це відома проблема «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
Повернути поточний вміст базового буфера.