Rust 中使用 tokio 異步操作 IO

請注意,異步操作標準 IO 請在 Tokio 的運行時上下文中使用,它們需要 Tokio 的一些特性。否則會發生 panic。

tokio 適合 IO 等待比較多的場景,不適合 CPU 密集型場景,不適合讀取大量的文件。它比較適合在網絡應用。

標準的輸入輸出簡單使用

use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> io::Result<()> {
    let mut stdout = io::stdout();
    stdout
        .write_all("請輸入您的暱稱,退出請輸入q\n".as_bytes())
        .await?;
    let mut stdin = io::stdin();
    loop {
        let mut buf = vec![0; 1024];
        let n = match stdin.read(&mut buf).await {
            Err(_) | Ok(0) => break,
            Ok(n) => n,
        };
        buf.truncate(n);
        let content = String::from_utf8_lossy(&buf).into_owned();
        let content = content.trim_end_matches("\r\n");
        if content == "q" {
            break;
        }
        println!("the input is {:?}", content);
    }
    Ok(())
}

標準 IO 和文件結合起來,演示讀文件內容

use tokio::{
    fs::File,
    io::{self, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader},
};
#[tokio::main]
async fn main() -> io::Result<()> {
    let mut stdout = io::stdout();
    // 小提示:字符串中包含\n,在窗口中直接顯示文本,不包含,需要按回車才顯示。
    stdout
        .write_all("打印文件內容,請輸入文件名稱,退出請輸入q\n".as_bytes())
        .await?;
    let mut stdin = io::stdin();
    loop {
        let mut buf = vec![0; 1024];
        let n = match stdin.read(&mut buf).await {
            Err(_) | Ok(0) => break,
            Ok(n) => n,
        };
        buf.truncate(n);
        let content = String::from_utf8_lossy(&buf).into_owned();
        let content = content.trim_end_matches("\r\n");
        if content == "q" {
            break;
        }
        println!("the input is {:?}", content);
        let f = File::open(content).await?;
        let mut reader = BufReader::new(f);
        let mut buffer = String::new();
        reader.read_to_string(&mut buffer).await?;
        println!("The content: {:?}", buffer);
    }
    Ok(())
}

從標準輸入中讀取內容,然後寫入到文件中

use tokio::{
    fs::File,
    io::{self, AsyncReadExt, AsyncWriteExt, BufWriter},
};
#[tokio::main]
async fn main() -> io::Result<()> {
    let mut stdout = io::stdout();
    // 小提示:字符串中包含\n,在窗口中直接顯示文本,不包含,需要按回車才顯示。
    stdout
        .write_all("請輸入將要創建文件名稱,退出請輸入q\n".as_bytes())
        .await?;
    let mut filename = String::new();
    let mut stdin = io::stdin();
    loop {
        let mut buf = vec![0; 1024];
        let n = match stdin.read(&mut buf).await {
            Err(_) | Ok(0) => break,
            Ok(n) => n,
        };
        buf.truncate(n);
        let content = String::from_utf8_lossy(&buf).into_owned();
        let content = content.trim_end_matches("\r\n");
        if content == "q" {
            break;
        }
        if content.len() > 0 {
            filename = content.to_owned();
            break;
        }
    }
    let f = File::create(filename.as_str()).await?;
    let mut writer = BufWriter::new(f);
    stdout
        .write_all("請輸入你要寫入的內容,退出請輸入q\n".as_bytes())
        .await?;
    loop {
        let mut buf = vec![0; 1024];
        let n = match stdin.read(&mut buf).await {
            Err(_) | Ok(0) => break,
            Ok(n) => n,
        };
        buf.truncate(n);
        let content = String::from_utf8_lossy(&buf).into_owned();
        let content = content.trim_end_matches("\r\n");
        if content == "q" {
            break;
        }
        println!("the input is {:?}", content);
        writer.write(content.as_bytes()).await?;
        writer.write(b"\n").await?;
    }
    writer.flush().await?;
    Ok(())
}

它提供一些有用的方法:

read_to_end,讀取流中的所有字節,直到碰到 EOF。

write,將緩衝區中的數據寫入到流中,返回寫入的字節數。

write_all,將整個緩衝區中的數據都寫入到流中。

copy,從流中讀取的內容再寫入到流中。使用這個函數可以方便的實現回聲功能。

理解之後,會感覺設計的非常妙。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/8XvIyByXqkYz2WlPU0XMqA