Модуль io
Трейты, вспомогательные средства и определения типов для асинхронной функциональности ввода-вывода.
Этот модуль является асинхронной версией std::io. В основном он определяет два трейта: AsyncRead и AsyncWrite, которые являются асинхронными версиями трейтов Read и Write из стандартной библиотеки.
AsyncRead и AsyncWrite
Как и трейты Read и Write стандартной библиотеки, AsyncRead и AsyncWrite предоставляют наиболее общий интерфейс для чтения и записи ввода и вывода. Однако, в отличие от трейтов стандартной библиотеки, они асинхронны — это означает, что чтение из или запись в тип tokio::io будет уступать планировщику Tokio, когда ввод-вывод не готов, вместо блокировки. Это позволяет другим задачам выполняться во время ожидания ввода-вывода.
Другое отличие заключается в том, что AsyncRead и AsyncWrite содержат только основные методы, необходимые для предоставления асинхронной функциональности чтения и записи. Вместо этого служебные методы определены в трейтах-расширениях AsyncReadExt и AsyncWriteExt. Эти трейты автоматически реализуются для всех значений, которые реализуют AsyncRead и AsyncWrite соответственно.
Конечные пользователи редко будут взаимодействовать напрямую с AsyncRead и AsyncWrite. Вместо этого они будут использовать асинхронные функции, определенные в трейтах-расширениях. Ожидается, что авторы библиотек будут реализовывать AsyncRead и AsyncWrite, чтобы предоставлять типы, которые ведут себя как потоки байтов.
Даже с этими различиями, трейты AsyncRead и AsyncWrite Tokio можно использовать почти точно так же, как Read и Write стандартной библиотеки. Большинство типов в стандартной библиотеке, которые реализуют Read и Write, имеют асинхронные эквиваленты в tokio, которые реализуют AsyncRead и AsyncWrite, такие как File и TcpStream.
Например, документация стандартной библиотеки представляет Read, демонстрируя чтение некоторых байтов из std::fs::File. Мы можем сделать то же самое с tokio::fs::File:
use tokio::io::{self, AsyncReadExt}; use tokio::fs::File; #[tokio::main] async fn main() -> io::Result<()> { let mut f = File::open("foo.txt").await?; let mut buffer = [0; 10]; // читаем до 10 байт let n = f.read(&mut buffer).await?; println!("Байты: {:?}", &buffer[..n]); Ok(()) }
Буферизированные читатели и писатели
Интерфейсы на основе байтов неудобны и могут быть неэффективными, так как нам потребуется делать почти постоянные вызовы к операционной системе. Чтобы помочь с этим, std::io поставляется с поддержкой буферизированных читателей и писателей, и, следовательно, tokio::io тоже.
Tokio предоставляет асинхронную версию трейта std::io::BufRead — AsyncBufRead; а также асинхронные структуры BufReader и BufWriter, которые оборачивают читателей и писателей. Эти обертки используют буфер, уменьшая количество вызовов и предоставляя более удобные методы для доступа именно к тому, что вам нужно.
Например, BufReader работает с трейтом AsyncBufRead, чтобы добавить дополнительные методы к любому асинхронному читателю:
use tokio::io::{self, BufReader, AsyncBufReadExt}; use tokio::fs::File; #[tokio::main] async fn main() -> io::Result<()> { let f = File::open("foo.txt").await?; let mut reader = BufReader::new(f); let mut buffer = String::new(); // читаем строку в buffer reader.read_line(&mut buffer).await?; println!("{}", buffer); Ok(()) }
BufWriter не добавляет новых способов записи; он просто буферизует каждый вызов write. Однако вы должны вызывать flush для BufWriter, чтобы убедиться, что все буферизированные данные записаны.
use tokio::io::{self, BufWriter, AsyncWriteExt}; use tokio::fs::File; #[tokio::main] async fn main() -> io::Result<()> { let f = File::create("foo.txt").await?; { let mut writer = BufWriter::new(f); // Записываем байт в буфер. writer.write(&[42u8]).await?; // Сбрасываем буфер перед выходом из области видимости. writer.flush().await?; } // Если не сброшено или не закрыто, содержимое буфера отбрасывается при удалении. Ok(()) }
Реализация AsyncRead и AsyncWrite
Поскольку это трейты, мы можем реализовать AsyncRead и AsyncWrite для наших собственных типов. Обратите внимание, что эти трейты должны реализовываться только для неблокирующих типов ввода-вывода, которые интегрируются с системой типов futures. Другими словами, эти типы никогда не должны блокировать поток, и вместо этого текущая задача уведомляется, когда ресурс ввода-вывода готов.
Преобразование в Stream/Sink и обратно
Часто удобно инкапсулировать чтение и запись байтов в Stream или Sink данных.
Tokio предоставляет простые обертки для преобразования AsyncRead в Stream и обратно в крейте tokio-util, см. ReaderStream и StreamReader.
Также существуют служебные трейты, которые абстрагируют асинхронную буферизацию, необходимую для написания собственных адаптеров для кодирования и декодирования байтов в/из ваших структурированных данных, позволяя преобразовать что-то, что реализует AsyncRead/AsyncWrite, в Stream/Sink, см. Decoder и Encoder в модуле tokio-util::codec.
Стандартный ввод и вывод
Tokio предоставляет асинхронные API для стандартного ввода, вывода и ошибки. Эти API очень похожи на предоставляемые std, но они также реализуют AsyncRead и AsyncWrite.
Обратите внимание, что API стандартного ввода/вывода должны использоваться в контексте среды выполнения Tokio, так как они требуют функций, специфичных для Tokio, чтобы функционировать. Вызов этих функций вне среды выполнения Tokio вызовет панику.
Реэкспорт из std
Дополнительно Error, ErrorKind, Result и SeekFrom реэкспортируются из std::io для удобства использования.
#![allow(unused)] fn main() { pub use std::io::Error; pub use std::io::ErrorKind; pub use std::io::Result; pub use std::io::SeekFrom; }
Модули
| Имя | Флаги | Описание |
|---|---|---|
bsd | FreeBSD и net | Специфичные для BSD типы ввода-вывода. |
unix | Unix и net | Асинхронные структуры ввода-вывода, специфичные для Unix-подобных ОС. |
Структуры
| Имя | Флаги | Описание |
|---|---|---|
BufReader | io-util | Добавляет буферизацию любому читателю. |
BufStream | io-util | Оборачивает тип, который является AsyncWrite и AsyncRead, и буферизует его ввод и вывод. |
BufWriter | io-util | Оборачивает писатель и буферизует его вывод. |
Chain | io-util | Поток для метода chain. |
DuplexStream | io-util | Дуплексный канал для чтения и записи байтов в памяти. |
Empty | io-util | Игнорирует любые данные, записанные через AsyncWrite, и всегда будет пуст (возвращает ноль байт) при чтении через AsyncRead. |
Interest | См. описание | Интерес события готовности. |
Join | io-util | Объединяет два значения, реализующих AsyncRead и AsyncWrite, в один дескриптор. |
Lines | io-util | Читает строки из AsyncBufRead. |
ReadBuf | Обертка вокруг байтового буфера, который постепенно заполняется и инициализируется. | |
ReadHalf | io-util | Читаемая половина значения, возвращенного из split. |
Ready | См. описание | Описывает состояние готовности ресурса ввода-вывода. |
Repeat | io-util | Асинхронный читатель, который бесконечно повторяет один байт. |
SimplexStream | io-util | Однонаправленный канал для чтения и записи байтов в памяти. |
Sink | io-util | Асинхронный писатель, который будет перемещать данные в пустоту. |
Split | io-util | Разделитель для метода split. |
Stderr | io-std | Дескриптор потока стандартной ошибки процесса. |
Stdin | io-std | Дескриптор потока стандартного ввода процесса. |
Stdout | io-std | Дескриптор потока стандартного вывода процесса. |
Take | io-util | Поток для метода take. |
WriteHalf | io-util | Записываемая половина значения, возвращенного из split. |
Трейты
| Имя | Флаги | Описание |
|---|---|---|
AsyncBufRead | Асинхронно читает байты. | |
AsyncBufReadExt | io-util | Трейт-расширение, добавляющий служебные методы к типам AsyncBufRead. |
AsyncRead | Читает байты из источника. | |
AsyncReadExt | io-util | Читает байты из источника. |
AsyncSeek | Асинхронно перемещается по байтам. | |
AsyncSeekExt | io-util | Трейт-расширение, добавляющий служебные методы к типам AsyncSeek. |
AsyncWrite | Асинхронно записывает байты. | |
AsyncWriteExt | io-util | Записывает байты в приемник. |
Функции
| Имя | Флаги | Описание |
|---|---|---|
copy | io-util | Асинхронно копирует все содержимое читателя в писатель. |
copy_bidirectional | io-util | Копирует данные в обоих направлениях между a и b. |
copy_bidirectional_with_sizes | io-util | Копирует данные в обоих направлениях между a и b с использованием буферов указанного размера. |
copy_buf | io-util | Асинхронно копирует все содержимое читателя в писатель. |
duplex | io-util | Создает новую пару DuplexStream, которые ведут себя как пара соединенных сокетов. |
empty | io-util | Создает значение, которое всегда находится в EOF при чтении и игнорирует все записанные данные. |
join | io-util | Объединяет два значения, реализующих AsyncRead и AsyncWrite, в один дескриптор. |
repeat | io-util | Создает экземпляр асинхронного читателя, который бесконечно повторяет один байт. |
simplex | io-util | Создает однонаправленный буфер, который действует как канал в памяти. |
sink | io-util | Создает экземпляр асинхронного писателя, который успешно потребляет все данные. |
split | io-util | Разделяет одно значение, реализующее AsyncRead + AsyncWrite, на отдельные дескрипторы AsyncRead и AsyncWrite. |
stderr | io-std | Создает новый дескриптор стандартной ошибки текущего процесса. |
stdin | io-std | Создает новый дескриптор стандартного ввода текущего процесса. |
stdout | io-std | Создает новый дескриптор стандартного вывода текущего процесса. |