Ch 21: BufRead
BufRead是提供缓冲读取能力的trait,基于Readtrait添加了面向行的读取功能。BufReader是实现BufRead的结构。
BufRead的主要优势:
- 减少系统调用,提高读取效率
- 提供行读取接口
- 支持按行迭代
2. BufRead trait定义
Section titled “2. BufRead trait定义”pub trait BufRead: Read { fn read_line(&mut self, buf: &mut String) -> Result<usize>;
fn lines(&mut self) -> Lines<Self>;
fn split(self, byte: u8) -> Split<Self>;
// 其他方法...}3. read_line方法
Section titled “3. read_line方法”逐行读取,包含换行符:
use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> { let data = b"hello\nworld\n"; let reader = BufReader::new(&data[..]);
let mut line = String::new(); // read_line 读取一行(包括换行符) let bytes_read = reader.read_line(&mut line)?;
println!("读取了 {} 字节", bytes_read); println!("内容: {:?}", line); println!("包含换行符: {}", line.ends_with('\n'));
Ok(())}4. lines方法
Section titled “4. lines方法”返回行的迭代器:
use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> { let data = b"line one\nline two\nline three\n"; let reader = BufReader::new(&data[..]);
// lines() 返回迭代器,自动去除换行符 for line in reader.lines() { println!("行: {}", line?); } // 输出: // 行: line one // 行: line two // 行: line three
Ok(())}5. split方法
Section titled “5. split方法”按字节分割:
use std::io::{BufRead, BufReader, Split};
fn main() -> std::io::Result<()> { let data = b"hello world rust"; let reader = BufReader::new(&data[..]);
// split 按空格分割 let mut split_iter = reader.split(b' ');
// 第一个元素 if let Some(Ok(token)) = split_iter.next() { println!("第一个token: {}", String::from_utf8_lossy(&token)); }
// 收集剩余 let tokens: Vec<Result<Vec<u8>, _>> = split_iter.collect(); println!("剩余tokens: {:?}", tokens.len());
Ok(())}6. split实战:读取逗号分隔数据
Section titled “6. split实战:读取逗号分隔数据”use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> { let data = "name,age,city\nAlice,30,NYC\nBob,25,LA\n"; let reader = BufReader::new(data.as_bytes());
for line in reader.lines() { let line = line?; // 跳过表头 if line.starts_with("name") { continue; }
let fields: Vec<&str> = line.split(',').collect(); if fields.len() >= 3 { println!("姓名: {}, 年龄: {}, 城市: {}", fields[0], fields[1], fields[2]); } }
Ok(())}7. read_line与lines的区别
Section titled “7. read_line与lines的区别”use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> { let data = b"hello\nworld\n"; let reader = BufReader::new(&data[..]);
// read_line 保留换行符 let mut s1 = String::new(); reader.read_line(&mut s1)?; println!("read_line: {:?}", s1); // "hello\n"
// lines 不保留换行符 // 注意:reader已经被read_line消耗了一部分 // 实际中不要混合使用
Ok(())}8. matches查找匹配
Section titled “8. matches查找匹配”BufRead没有直接提供matches方法,但可以用split实现:
use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> { let data = b"error: file not found\ninfo: loading\nerror: out of memory\n"; let reader = BufReader::new(&data[..]);
for line in reader.lines() { let line = line?; if line.starts_with("error:") { println!("错误: {}", &line[6..].trim()); } }
Ok(())}9. 逐字符读取
Section titled “9. 逐字符读取”use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> { let data = b"hello"; let reader = BufReader::new(&data[..]);
let mut chars = Vec::new(); let mut buf = [0u8; 1];
while reader.read(&mut buf)? > 0 { chars.push(buf[0] as char); }
println!("字符: {:?}", chars);
Ok(())}10. 使用BufReader包装File
Section titled “10. 使用BufReader包装File”use std::fs::File;use std::io::{BufRead, BufReader};
fn main() -> std::io::Result<()> { // 创建测试文件 std::fs::write("test.txt", "line 1\nline 2\nline 3\n")?;
let file = File::open("test.txt")?; let reader = BufReader::new(file);
for line in reader.lines() { println!("{}", line?); }
// 清理 std::fs::remove_file("test.txt")?;
Ok(())}11. buffered_lines获取缓冲行
Section titled “11. buffered_lines获取缓冲行”BufRead提供lines()但不提供直接的缓冲行访问。可以通过fill_buf和consume手动实现:
use std::io::{BufRead, BufReader, Result};
fn main() -> Result<()> { let data = b"first line\nsecond line\nthird"; let mut reader = BufReader::new(&data[..]);
loop { // fill_buf 返回当前缓冲区的引用 let buf = reader.fill_buf()?;
if buf.is_empty() { break; }
// 查找第一个换行符 if let Some(pos) = memchr::memchr(b'\n', buf) { println!("行: {:?}", String::from_utf8_lossy(&buf[..pos])); // consume 消费已读取的字节 reader.consume(pos + 1); } else { // 没有换行符,消费所有数据 println!("行(无换行): {:?}", String::from_utf8_lossy(buf)); reader.consume(buf.len()); } }
Ok(())}12. 常见用法
Section titled “12. 常见用法”use std::io::{self, BufRead};
fn main() -> io::Result<()> { let stdin = io::stdin();
println!("输入一些文字,按Ctrl+D结束:");
for line in stdin.lock().lines() { let line = line?; if line.is_empty() { continue; } println!("你输入了: {}", line); }
Ok(())}13. BufRead实现者
Section titled “13. BufRead实现者”| 类型 | 说明 |
|---|---|
BufReader<T> | 带缓冲的读取器 |
std::io::stdin().lock() | 标准输入加锁后 |
io::Cursor<Vec<u8>> | 内存缓冲区 |
14. 总结
Section titled “14. 总结”今天我们学习了BufRead trait:
- read_line - 读取一行,包含换行符
- lines - 返回行的迭代器,自动去除换行符
- split - 按字节分割,返回迭代器
- fill_buf - 获取当前缓冲区的引用
- consume - 消费已读取的字节
BufRead是处理文本输入的强大工具,特别适合逐行读取文本文件。