首页 > 其他分享 >rust-BufReader逐字符读取

rust-BufReader逐字符读取

时间:2024-09-28 14:16:05浏览次数:6  
标签:BufReader 读取 self let io buf rust MyReader

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_bufconsume结合起来,就可以逐字节读取了:

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 {
            // Your code here
            println!("{}", c);
        }
        let len = buf.len();
        drop(buf);
        cin.consume(len);
    }
}

输入:

abc

输出:

97
98
99
10

最后的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);
    }
}

也可以写一个迭代器来实现类似于getcharpeek的效果:

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);
    }
}

输入:

abc

输出:

97
97
98
99
10

或者复杂一点的,减少调用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

标签:BufReader,读取,self,let,io,buf,rust,MyReader
From: https://www.cnblogs.com/searchstar/p/18437910

相关文章

  • rust print固定宽度左边补零
    参考:https://doc.rust-lang.org/std/fmt/任意类型fnmain(){println!("{:0>3}",2333);println!("{:0>3}",233);println!("{:0>3}",23);println!("{:0>3}",2);println!("{:0>3}"......
  • Rust文件操作
    文件管理mkdirhttps://doc.rust-lang.org/std/fs/fn.create_dir.htmlmkdir-phttps://doc.rust-lang.org/std/fs/fn.create_dir_all.htmlmvhttps://doc.rust-lang.org/std/fs/fn.rename.html临时文件/目录https://crates.io/crates/tempfile临时目录:https://docs.rs/temp......
  • rust运行shell命令并获取输出
    usestd::io::{BufReader,BufRead};usestd::process::{self,Command,Stdio};fnmain(){ls();ps();xargs();time();iostat();}//不带参数命令fnls(){letoutput=Command::new("ls").output().expect("执行异常,提示");......
  • rust打印变量类型
    可以试试std::any::type_name。注意,这个是unstable的。usestd::collections::HashSet;fnprint_type_of<T>(_:&T){println!("{}",std::any::type_name::<T>())}fnmain(){letmuts=HashSet::new();letve=vec![1,2,1,3,2,......
  • rust交换数组中的两个元素
    不可以直接用std::mem::swap,因为这个函数需要拿两个可变引用,但是不可以同时拿两个这个数组的可变引用。所以要么手写:lettmp=a[i];a[i]=a[j];a[j]=tmp;要么用Vec::swap:a.swap(i,j);其内部实现:fnswap(&mutself,a:usize,b:usize){unsafe{//......
  • rust二分搜索
    如果要二分搜索某个特定值,可以用binary_search:https://doc.rust-lang.org/stable/std/primitive.slice.html#method.binary_search如果要实现C++里的lower_bound和upper_bound类似的功能,可以用partition_point:https://doc.rust-lang.org/stable/std/primitive.slice.html#meth......
  • Rust索引String
    Rust的String里其实是UTF-8编码的,而UTF-8是变长编码,因此会导致Rust索引String时,可能是索引第k个UTF-8字符(需要遍历字符串),也可能是索引第k个字节。因此,Rust不支持直接用下标来索引String。如果要找到第k个UTF-8字符:s.chars().nth(k)如果要找到第k个字节:letx:u8=s.as_bytes......
  • 自制CANTool_DBC_Layout仿制_布局读取Signal(三)
    1、读取DBC中解析格式空格问题报错解决方法原来解析方式:BO_258EPS_CANFD_StrWhlASts:8Test有的DBC中数据格式:BO_80GW_50:8GW(多了一个空格)解析匹配规则修订为:stringMessageRegex=@"BO_\s+(\d+)\s+(\w+)\s*:\s*(\d+)\s+(\w+)";2、使用C#自制DBC布局--UI......
  • 01.SpringBoot开发杂记-使用工具类,静态读取配置文件中的配置的写法
    使用工具类,静态读取配置文件中的配置的写法@ComponentpublicclassConfigUtils{privatestaticConfigUtilsinstance;//单例模式持有当前工具类的实例privateConfigUtils(){}@Value("${system.uploadPath}")privateStringuploadPath;//@Value注解......
  • springFactoriesLoader作用是读取配置文件
    `SpringFactoriesLoader`是Spring框架中的一个类,用于从`META-INF/spring.factories`文件中加载配置。这是一个非常强大的机制,使得Spring能够通过查找类路径上的配置文件,动态地发现和加载特定的组件或服务。在Spring自动注入(自动配置)中,`SpringFactoriesLoader`起到了以......