rust BufReader逐字符读取
阅读量:
searchstar
2021-12-03 20:05:20
Categories:
Tags:
BufReader有一个fill_buf
的方法:
fn fill_buf(&mut self) -> Result<&[u8]>
|
它可以返回它的内部buffer,如果buffer是空的,就填入更多数据再返回。这样我们就可以逐个读取其内部buffer的字符,且不需要额外申请空间了。
通过fill_buf
返回的buffer处理完了一些数据之后,可以通过consume
来告诉BufReader这些数据已经处理完了:
fn consume(&mut self, amt: usize)
|
它将前amt
个字节从BufReader的buffer里删掉。
把fill_buf
和consume
结合起来,就可以逐字节读取了:
use std::io::{self, BufRead, BufReader};
fn main() { let mut cin = BufReader::new(io::stdin()); while let Ok(buf) = cin.fill_buf() { if buf.is_empty() { break; } for c in buf { println!("{}", c); } let len = buf.len(); drop(buf); cin.consume(len); } }
|
输入:
输出:
最后的10
是换行符LF
。
可以用闭包做一个wrapper:
use std::io::{self, BufRead, BufReader};
fn main() { let mut cin = BufReader::new(io::stdin()); let peek = |r: &mut BufReader<_>| -> io::Result<Option<u8>> { let buf = r.fill_buf()?; if buf.is_empty() { Ok(None) } else { Ok(Some(buf[0])) } }; while let Ok(Some(c)) = peek(&mut cin) { println!("{}", c); cin.consume(1); } }
|
也可以写一个迭代器来实现类似于getchar
和peek
的效果:
use std::io::{self, Read, BufRead, BufReader};
struct MyReader<T> { r: BufReader<T>, }
impl<T> From<BufReader<T>> for MyReader<T> { fn from(r: BufReader<T>) -> MyReader<T> { MyReader{r} } }
impl<T: Read> MyReader<T> { fn peek(&mut self) -> io::Result<Option<u8>> { let buf = self.r.fill_buf()?; if buf.is_empty() { Ok(None) } else { Ok(Some(buf[0])) } } }
impl<T: Read> Iterator for MyReader<T> { type Item = io::Result<u8>; fn next(&mut self) -> Option<Self::Item> { let res = self.r.fill_buf(); match res { Ok(buf) => { if buf.is_empty() { None } else { let ret = buf[0]; self.r.consume(1); Some(Ok(ret)) } }, Err(e) => Some(Err(e)) } } }
fn main() { let mut cin = MyReader::from(BufReader::new(io::stdin())); println!("{}", cin.peek().unwrap().unwrap()); while let Some(Ok(c)) = cin.next() { println!("{}", c); } }
|
输入:
输出:
或者复杂一点的,减少调用consume
的次数(不知道会不会变快):
use std::io::{self, Read, BufRead, BufReader};
struct MyReader<T> { r: BufReader<T>, head: usize, }
impl<T> From<BufReader<T>> for MyReader<T> { fn from(r: BufReader<T>) -> MyReader<T> { MyReader{r, head: 0} } }
impl<T: Read> Iterator for MyReader<T> { type Item = io::Result<u8>; fn next(&mut self) -> Option<Self::Item> { if self.head == self.r.buffer().len() { self.r.consume(self.head); let res = self.r.fill_buf(); match res { Ok(buf) => { if buf.is_empty() { return None; } self.head = 0; }, Err(e) => return Some(Err(e)), } } let ret = Some(Ok(self.r.buffer()[self.head])); self.head += 1; return ret; } }
fn main() { let mut cin = MyReader::from(BufReader::new(io::stdin())); while let Some(Ok(c)) = cin.next() { println!("{}", c); } }
|
参考文献:rust BufReader官方文档:https://doc.rust-lang.org/stable/std/io/struct.BufReader.html