Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Модуль 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::BufReadAsyncBufRead; а также асинхронные структуры 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;
}

Модули

ИмяФлагиОписание
bsdFreeBSD и netСпецифичные для BSD типы ввода-вывода.
unixUnix и netАсинхронные структуры ввода-вывода, специфичные для Unix-подобных ОС.

Структуры

ИмяФлагиОписание
BufReaderio-utilДобавляет буферизацию любому читателю.
BufStreamio-utilОборачивает тип, который является AsyncWrite и AsyncRead, и буферизует его ввод и вывод.
BufWriterio-utilОборачивает писатель и буферизует его вывод.
Chainio-utilПоток для метода chain.
DuplexStreamio-utilДуплексный канал для чтения и записи байтов в памяти.
Emptyio-utilИгнорирует любые данные, записанные через AsyncWrite, и всегда будет пуст (возвращает ноль байт) при чтении через AsyncRead.
InterestСм. описаниеИнтерес события готовности.
Joinio-utilОбъединяет два значения, реализующих AsyncRead и AsyncWrite, в один дескриптор.
Linesio-utilЧитает строки из AsyncBufRead.
ReadBufОбертка вокруг байтового буфера, который постепенно заполняется и инициализируется.
ReadHalfio-utilЧитаемая половина значения, возвращенного из split.
ReadyСм. описаниеОписывает состояние готовности ресурса ввода-вывода.
Repeatio-utilАсинхронный читатель, который бесконечно повторяет один байт.
SimplexStreamio-utilОднонаправленный канал для чтения и записи байтов в памяти.
Sinkio-utilАсинхронный писатель, который будет перемещать данные в пустоту.
Splitio-utilРазделитель для метода split.
Stderrio-stdДескриптор потока стандартной ошибки процесса.
Stdinio-stdДескриптор потока стандартного ввода процесса.
Stdoutio-stdДескриптор потока стандартного вывода процесса.
Takeio-utilПоток для метода take.
WriteHalfio-utilЗаписываемая половина значения, возвращенного из split.

Трейты

ИмяФлагиОписание
AsyncBufReadАсинхронно читает байты.
AsyncBufReadExtio-utilТрейт-расширение, добавляющий служебные методы к типам AsyncBufRead.
AsyncReadЧитает байты из источника.
AsyncReadExtio-utilЧитает байты из источника.
AsyncSeekАсинхронно перемещается по байтам.
AsyncSeekExtio-utilТрейт-расширение, добавляющий служебные методы к типам AsyncSeek.
AsyncWriteАсинхронно записывает байты.
AsyncWriteExtio-utilЗаписывает байты в приемник.

Функции

ИмяФлагиОписание
copyio-utilАсинхронно копирует все содержимое читателя в писатель.
copy_bidirectionalio-utilКопирует данные в обоих направлениях между a и b.
copy_bidirectional_with_sizesio-utilКопирует данные в обоих направлениях между a и b с использованием буферов указанного размера.
copy_bufio-utilАсинхронно копирует все содержимое читателя в писатель.
duplexio-utilСоздает новую пару DuplexStream, которые ведут себя как пара соединенных сокетов.
emptyio-utilСоздает значение, которое всегда находится в EOF при чтении и игнорирует все записанные данные.
joinio-utilОбъединяет два значения, реализующих AsyncRead и AsyncWrite, в один дескриптор.
repeatio-utilСоздает экземпляр асинхронного читателя, который бесконечно повторяет один байт.
simplexio-utilСоздает однонаправленный буфер, который действует как канал в памяти.
sinkio-utilСоздает экземпляр асинхронного писателя, который успешно потребляет все данные.
splitio-utilРазделяет одно значение, реализующее AsyncRead + AsyncWrite, на отдельные дескрипторы AsyncRead и AsyncWrite.
stderrio-stdСоздает новый дескриптор стандартной ошибки текущего процесса.
stdinio-stdСоздает новый дескриптор стандартного ввода текущего процесса.
stdoutio-stdСоздает новый дескриптор стандартного вывода текущего процесса.