std::io

Cursor

Cursor把内存数据 &[u8] → 变成可读写、可seek的虚拟文件(模拟文件、网络读写)

new

创建一个新的游标来包装所提供的底层内存缓冲区

use std::io::Cursor;

fn main() {
    // 1. 从 Vec<u8> 创建
    let cursor1 = Cursor::new(vec![1, 2, 3, 4]);
    println!("Cursor1: {:?}", cursor1);
    
    // 2. 从字节切片创建
    let data = [1, 2, 3, 4];
    let cursor2 = Cursor::new(&data[..]);
    println!("Cursor2: {:?}", cursor2);
    
    // 3. 从 String 创建
    let cursor3 = Cursor::new(String::from("hello"));
    println!("Cursor3: {:?}", cursor3);
    
    // 4. 从 &str 创建
    let text = "hello";
    let cursor4 = Cursor::new(&text[..]);
    println!("Cursor4: {:?}", cursor4);
}
Cursor1: Cursor { inner: [1, 2, 3, 4], pos: 0 }
Cursor2: Cursor { inner: [1, 2, 3, 4], pos: 0 }
Cursor3: Cursor { inner: "hello", pos: 0 }
Cursor4: Cursor { inner: "hello", pos: 0 }

获取数据

get_ref

获取游标中的数据不可变引用(cursor1)

use std::io::Cursor;

fn main() {
    let cursor1 = Cursor::new(vec![1, 2, 3, 4]);

    println!("Cursor1: {:?}", cursor1.get_ref());
}
Cursor1: [1, 2, 3, 4]

get_mut

获取游标中的数据可变引用(cursor1)

use std::io::Cursor;

fn main() {
    let mut cursor1 = Cursor::new(vec![1, 2, 3, 4]);

    let data_ref = cursor1.get_mut();
    println!("Cursor1: {:?}", data_ref);
    data_ref[0] = 5;
    println!("Cursor1: {:?}", data_ref);
}
Cursor1: [1, 2, 3, 4]
Cursor1: [5, 2, 3, 4]

into_inner

提取cursor内部的[u8]数据,转移所有权

  • get_ref()用(&[u8])
  • into_inner()拿走所有权([u8])
use std::io::Cursor;

fn main() {
    let mut cursor = Cursor::new(b"hello");

    println!("{:?}", cursor);

    println!("{:?}", cursor.get_ref());

    println!("{:?}", cursor.into_inner());
}
Cursor { inner: [104, 101, 108, 108, 111], pos: 0 }
[104, 101, 108, 108, 111]
[104, 101, 108, 108, 111]

游标设置

游标设置对get_refget_mut无效

position

获取游标位置

use std::io::Cursor;

fn main() {
    let cursor1 = Cursor::new(vec![1, 2, 3, 4]);
    // 返回此游标的当前位置。
    println!("position: {}", cursor1.position());
    println!("Cursor1: {:?}", cursor1);
}
position: 0
Cursor1: Cursor { inner: [1, 2, 3, 4], pos: 0 }

set_position

设置游标位置
超出范围不报错

use std::io::Cursor;

fn main() {
    let mut cursor1 = Cursor::new(vec![1, 2, 3, 4]);
    // 设置游标位置
    cursor1.set_position(2);
    println!("Cursor1: {:?}", cursor1);
}
Cursor1: Cursor { inner: [1, 2, 3, 4], pos: 2 }

seek

移动游标位置,需要配合SeekFrom

SeekFrom::Start

从文件开头开始移动,和set_position效果一样,返回移动后的位置Result<u64>

use std::io::{Cursor, Seek, SeekFrom};

fn main() {
    let mut cursor = Cursor::new(vec![1, 2, 3, 4]);
    
    let s = cursor.seek(SeekFrom::Start(2));
    println!("s: {:?}", s);   
}
s: Ok(2)

SeekFrom::End

从文件末尾开始移动, 最后一位是-1
当移动位置小于0时,返回Err(Error)

use std::io::{Cursor, Seek, SeekFrom};

fn main() {
    let mut cursor = Cursor::new(vec![1, 2, 3, 4]);

    let s = cursor.seek(SeekFrom::End(0)); // 移动到末尾
    println!("{:?}", s);
    println!("{:?}", cursor.position());

    let s = cursor.seek(SeekFrom::End(-1)); // 移动到元素最后一个索引位置
    println!("{:?}", s);
    println!("{:?}", cursor.position());

    let s = cursor.seek(SeekFrom::End(-3));
    println!("{:?}", s);
    println!("{:?}", cursor.position());

    let s = cursor.seek(SeekFrom::End(-16));
    println!("{:?}", s);
    println!("{:?}", cursor.position());
}
Ok(4)
4
Ok(3)
3
Ok(1)
1
Err(Error { kind: InvalidInput, message: "invalid seek to a negative or overflowing position" })
1

SeekFrom::Current

相对于当前位置进行移动

use std::io::{Cursor, Seek, SeekFrom};

fn main() {
    let mut cursor = Cursor::new(vec![1, 2, 3, 4]);

    // 移动到下标2的位置
    cursor.set_position(2); // 和seek(SeekFrom::Start(2))效果一样
    println!("{:?}", cursor.position());

    // 下标2的位置s+1,移动到下标3的位置
    let s = cursor.seek(SeekFrom::Current(1));
    println!("{:?}", s);

    // 下标3的位置-3,移动到下标0的位置
    let s = cursor.seek(SeekFrom::Current(-3));
    println!("{:?}", s);

    // 下标0的位置-1,超出范围报错
    let s = cursor.seek(SeekFrom::Current(-1));
    println!("{:?}", s);
}
2
Ok(3)
Ok(0)
Err(Error { kind: InvalidInput, message: "invalid seek to a negative or overflowing position" })

读写操作

Read

read

read() 不会多读,最多读满缓冲区(也就是buffer的大小)

&buffer[..n])必须使用这个转为字符串,n是读取到的字节数

read 读到多少,就用多少

  • buffer = [真实数据(10) + 空数据0(10)]
  • buffer[..n] = [真实数据(10)]
use std::io::{Read, Cursor};

fn main() {
    // 内存里的一段数据(就当是文件内容)
    let data = b"hello rust";

    // 1. 把 data 包成 Cursor(变成可读对象)
    let mut cursor = Cursor::new(data);

    // 2. 创建一个缓冲区,用来接收读到的数据
    let mut buffer = [0u8; 20];

    // 3. 调用 read() 读取!
    let n = cursor.read(&mut buffer).unwrap();

    // 输出结果
    println!("读到字节数: {}", n);
    println!("buffer: {:?}", buffer);
  	// 必须使用&buffer[..n])转为字符串,因为buffer大于数据的话,后面都是用0补充的
    println!("内容: {}", String::from_utf8_lossy(&buffer[..n]));
}
读到字节数: 10
buffer: [104, 101, 108, 108, 111, 32, 114, 117, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
内容: hello rust

buffer小于内容大小

只会读取设置的大小

use std::io::{Read, Cursor};

fn main() {
    // 内存里的一段数据(就当是文件内容)
    let data = b"hello rust";

    // 1. 把 data 包成 Cursor(变成可读对象)
    let mut cursor = Cursor::new(data);

    let mut buffer = [0u8; 3];

    let n = cursor.read(&mut buffer).unwrap();

    // 输出结果
    println!("读到字节数: {}", n);
    println!("buffer: {:?}", buffer);
    println!("内容: {}", String::from_utf8_lossy(&buffer[..n]));
}
读到字节数: 3
buffer: [104, 101, 108]
内容: hel

read_to_end

读取所有数据到Vec,适合读取图片、文件、二进制、未知数据

  • 和read区别

    • 不用关心缓冲区大小

    • 自动读到完,不会漏、不会多

use std::io::{Read, Cursor};

fn main() {
    let data = b"hello rust";
    let mut cursor = Cursor::new(data);

    // 创建一个空 Vec,用来接收全部数据
    let mut buf = Vec::new();

    // read_to_end 直接读完所有内容
    let n = cursor.read_to_end(&mut buf).unwrap();

    println!("总字节数: {}", n);
    println!("buf: {:?}", buf);
    println!("完整内容: {}", String::from_utf8_lossy(&buf));
}
总字节数: 10
buf: [104, 101, 108, 108, 111, 32, 114, 117, 115, 116]
完整内容: hello rust

read_to_string

读取所有数据到 String,适合读取纯文本、JSON、HTML

  • 和read_to_end区别
    • 自动把字节转成字符串
    • 读取非UTF-8字符
use std::io::{Read, Cursor};

fn main() {
    let data = b"hello rust";
    let mut cursor = Cursor::new(data);

    // 创建一个空String,用来接收全部数据
    let mut buf = String::new();

    // read_to_string 直接读完所有内容
    let n = cursor.read_to_string(&mut buf).unwrap();

    println!("总字节数: {}", n);
    println!("buf: {:?}", buf);
}
总字节数: 10
buf: "hello rust"

read_exact

必须读满你给的缓冲区,少一个字节都直接报错

解析协议头、结构体、固定长度消息

  • 和read区别
    • read: 数据只有 5 字节,缓冲区大小是 10 字节,缓冲区后半部分还是0
    • read_exact: 想读 10 字节,但只有 5 字节,直接panic报错
use std::io::{Read, Cursor};

fn main() {
    let data = b"hello rust"; // 10 字节
    let mut cursor = Cursor::new(data);

    // 我要精确读 5 个字节
    let mut buf = [0u8; 5];  // 缓冲区大小 5

    cursor.read_exact(&mut buf).unwrap(); // 必须填满

    println!("读到: {:?}", &buf); // 前 5 字节
}
读到: [104, 101, 108, 108, 111]

Write

write

可能只写一部分,不保证写完

  • 网络 socket / 管道 / 阻塞流
    • 要写 100 字节,系统缓冲区满了, write() 只写进去 30 字节,返回 30
    • 剩下 70 字节 你需要自己再次调用 write 才能写完
use std::io::{Write, Cursor};

fn main() {
    // 创建一个空的 Cursor(基于 Vec<u8>)
    let mut cursor = Cursor::new(Vec::new());

    let s = cursor.write(b"hello write").unwrap();
    println!("写入字节: {}", s);
    // 获取内存里的数据
    let data = cursor.into_inner();
    println!("data: {}", String::from_utf8_lossy(&data));
}
写入字节: 11
data: hello write

write_all

保证一定全部写完,写不完就报错

  • write区别
    • write_all()自动循环 write,直到 100 字节全部写完
use std::io::{Cursor, Write};

fn main() {
    // 创建一个空的 Cursor(基于 Vec<u8>)
    let mut cursor = Cursor::new(Vec::new());

    cursor.write_all(b"hello write").unwrap();

    // 获取内存里的数据
    let data = cursor.into_inner();
    println!("data: {}", String::from_utf8_lossy(&data));
}
data: hello write

write_fmt

专门用来写格式化字符串(数字、变量、占位符)

  • write_fmt + format_args!实现
  • write!实现,本质内部还是write_fmt + format_args!实现
use std::io::{Write, Cursor};

fn main() {
    let mut cursor = Cursor::new(Vec::new());

    // 底层写法:必须用 format_args!
    cursor.write_fmt(format_args!("Hello {}\n", "Rust")).unwrap();

    // 简化写法:write! 宏(推荐!)
    write!(cursor, "今天温度: {}°C", 25).unwrap();

    let data = cursor.into_inner();
    println!("{}", String::from_utf8_lossy(&data));
}
Hello Rust
今天温度: 25°C

flush

把缓冲区的内容刷入到目标中(文件、网络、控制台)

  • 真的刷新
    • 遇到换行 \n → 自动 flush
    • 缓冲区满了 → 自动 flush
    • 程序结束(main 退出)→ 自动 flush
use std::io::{Write, Cursor};

fn main() {
    let mut cursor = Cursor::new(Vec::new());

    cursor.write(b"aaa").unwrap();

    // 立即输入到目标中
    cursor.flush().unwrap();

    println!("data: {}", String::from_utf8_lossy(cursor.get_ref()));
}
data: aaa

缓冲读取

以后只要用 Read / Write,一律套上 BufReader / BufWriter 加速!

BufReader

read() 是一个系统调用,要跨越用户态 ↔ 内核态边界

BufReader 一次批量读 8KB(默认)到用户态缓冲区,

use std::io::BufReader;
use std::fs::File;

let file = File::open("test.txt").unwrap();

// 套缓冲(加一层)
let mut reader = BufReader::new(file); 

// 方法和上面一样
reader.read(&mut buf)           // 老样子
reader.read_exact(&mut buf)     // 老样子
reader.read_to_end(&mut vec)    // 老样子
reader.read_to_string(&mut s)   // 老样子

BufReader按行读取

use std::io::BufRead; // 必须导入

for line in reader.lines() {
    println!("{}", line.unwrap());
}

BufWriter

BufWriter 不会立刻写入文件, 数据先存在内存缓冲区

需要调用flush或者文件关闭时才会自动刷入

  • BufWriter 工作规则:

    • 写的数据 < 8KB → 存在内存

    • 写的数据 ≥ 8KB自动刷入文件

    • 调用 .flush()强制刷入

use std::io::BufWriter;
use std::fs::File;

let file = File::create("out.txt").unwrap();
let mut writer = BufWriter::new(file);


writer.write(&buf)        // 老样子
writer.write_all(&buf)    // 老样子(最常用)
writer.write_fmt(...)     // 老样子
write!(&mut writer, "{}", x) // 老样子

writer.flush().unwrap(); // 强制写入磁盘

修改缓存大小

默认8kb(8192 字节)

  • 小文件:8KB(默认)

  • 普通文件:32KB / 64KB

  • 大文件、高吞吐量:128KB / 256KB / 512KB

use std::io::{BufReader, BufWriter, Read, Write};
use std::fs::File;

// 自定义 64KB 缓冲
let reader = BufReader::with_capacity(64 * 1024, file);
let writer = BufWriter::with_capacity(64 * 1024, file);

seek

BufReaderBufWriter也可以使用seek

let file = File::open("a.txt")?;
let mut buf_reader = BufReader::new(file);

// 你调用 seek
buf_reader.seek(SeekFrom::Start(5))?;

// 实际执行的是 ↓
// file.seek(...)

标准输入输出

标准输入io::stdin

键盘输入 / 管道输入

echo "abc"结尾会带\n换行符,所以读取的是4个字符

基础

和上面一样

  • stdin.read
  • stdin.read_to_end
  • stdin.read_to_string
  • stdin.read_exact
use std::io::{self, Read, Write};

fn main() {
    let mut stdin = io::stdin();

    let mut buf = [0; 10];
    let n = stdin.read(&mut buf).unwrap();
    println!("n: {}", n);
    println!("{:?}", &buf);
    print!("{}", String::from_utf8_lossy(&buf[..n]));
}
echo "abc" | cargo run
n: 4
[97, 98, 99, 10, 0, 0, 0, 0, 0, 0]
abc

read_line(无lock)只读一行

读取一行(直到换行),包含换行符 \n

use std::io::{self, Read};

fn main() {
    let mut stdin = io::stdin();

    let mut buf = String::new();
    let n = stdin.read_line(&mut buf).unwrap();
    println!("n: {}", n);
    println!("buf: {}", buf);
}
echo "abc" | cargo run

n: 4
abc

lock

io::stdin().lock()相当于BufReader::new(io::stdin())

lines(lock)按行读取

lines需要引入BufRead

use std::io::{self, BufRead};

fn main() {
  	// 使用lock需要引入BufRead
      
}
echo "abc\n123\nccc\n456" | cargo run

Ok("abc")
Ok("123")
Ok("ccc")
Ok("456")

read_line(有lock)只读一行

use std::io::{self, BufRead};

fn main() {
  	// 加了lock
    let mut stdin = io::stdin().lock();

    let mut buf = String::new();
    let n = stdin.read_line(&mut buf).unwrap();
    println!("n: {}", n);
    println!("buf: {}", buf);
}
echo "abc" | cargo run

n: 4
abc

BufRead + stdin

read_line(BufRead)只读一行

use std::io::{self, BufRead, BufReader};

fn main() {
    let mut stdin = BufReader::new(io::stdin());

    let mut buf = String::new();
    let n = stdin.read_line(&mut buf).unwrap();
    println!("n: {}", n);
    println!("buf: {}", buf);
}
echo "abc" | cargo run

n: 4
buf: abc

lines(BufRead)按行读取

use std::io::{self, BufRead, BufReader};

fn main() {
    let mut stdin = BufReader::new(io::stdin());

    for line in stdin.lines() {
        println!("line: {:?}", line);
    }
}
echo "abc\n123\nccc\n456" | cargo run

line: Ok("abc")
line: Ok("123")
line: Ok("ccc")
line: Ok("456")

标准输出io::stdout

  • write
  • write_all
  • write_fmt + format_args!
use std::io::{self, Write};

fn main() {
    let mut stdout = io::stdout();

    stdout.write(b"hello").unwrap();

    stdout.flush().unwrap();
}
hello%

lock

自带BufWriter, 相当于BufWriter::new(io::stdout());

use std::io::{self, Write};

fn main() {
    let mut stdout = io::stdout().lock();

    stdout.write_fmt(format_args!("hello {}", "word")).unwrap();

    stdout.flush().unwrap();
}
hello word% 

BufWriter

use std::io::{self, BufWriter, Write};

fn main() {
    let mut stdout = BufWriter::new(io::stdout());

    stdout.write_fmt(format_args!("hello {}", "word")).unwrap();

    stdout.flush().unwrap();
}
hello word% 

标准错误io::stderr

stderr不需要flush标准错误流(stderr)默认是:无缓冲(unbuffered)

  • write
  • write_all
  • write_fmt + format_args!
use std::io::{self, Write};

fn main() {
    let mut stderr = io::stderr();

    stderr.write(b"error test").unwrap();
}

验证

cargo run 2> a.txt 
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.10s
     Running `target/debug/test`
error test

编译之后执行

./target/debug/test 2> a.txt
error test

lock

自带BufWriter,相当于BufWriter::new(io::stderr())

use std::io::{self, Write};

fn main() {
    let mut stderr = io::stderr().lock();

    stderr.write(b"error test").unwrap();
}
error test% 

BufWriter

use std::io::{self, Write, BufWriter};

fn main() {
    let mut stderr = BufWriter::new(io::stderr());

    stderr.write(b"error test").unwrap();
}
error test% 

错误处理

  • 所有 IO 函数都返回 Result<T, Error>
  • ? 只能用在 返回 Result 的函数

直接panic

use std::io::{self, Write};

fn main() {
    let mut out = io::stdout();
    out.write(b"hello").unwrap(); // 出错就 panic
}

返回错误

use std::io::{self, Write};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut out = io::stdout();
    
    out.write(b"hello")?; // 错误直接返回,不崩溃
    
    Ok(())
}

match捕获

match out.write(b"hello") {
    Ok(_) => println!("成功"),
    Err(e) => eprintln!("写入失败:{}", e), // 优雅处理
}
posted @ 2026-04-14 02:08  lxd670  阅读(3)  评论(0)    收藏  举报