Io 在Rust中逐字读取文件

Io 在Rust中逐字读取文件,io,rust,Io,Rust,是否有一种惯用的方法在Rust中一次处理一个字符的文件 这大概就是我想要的: let mut f = io::BufReader::new(try!(fs::File::open("input.txt"))); for c in f.chars() { println!("Character: {}", c.unwrap()); } 但在Rust v1.6.0中仍然不稳定 我考虑过使用,但文件可能很大,我不想将其全部读入内存。这里有两种解决方案 首先,您可以复制Read::chars

是否有一种惯用的方法在Rust中一次处理一个字符的文件

这大概就是我想要的:

let mut f = io::BufReader::new(try!(fs::File::open("input.txt")));

for c in f.chars() {
    println!("Character: {}", c.unwrap());
}
但在Rust v1.6.0中仍然不稳定


我考虑过使用,但文件可能很大,我不想将其全部读入内存。

这里有两种解决方案

首先,您可以复制
Read::chars()
的实现并使用它;如果代码稳定下来,那么将代码移到标准库实现中就变得非常简单了

另一方面,您可以简单地逐行迭代(使用
f.lines()
),然后在每一行上使用
line.chars()
)来获取字符。这是一个有点黑客,但它肯定会工作


如果您只需要一个循环,那么可以将
flat_map()
与类似于
|line | line.chars()的lambda一起使用

1<代码>读取::字符

您可以复制实现,但它被标记为不稳定

错误发生位置的部分读/写的语义目前尚不清楚,可能会发生变化

因此,必须小心一些。无论如何,这似乎是最好的办法

2<代码>平面地图

平面图
备选方案未编译:

use std::io::{BufRead, BufReader};
use std::fs::File;

pub fn main() {
    let mut f = BufReader::new(File::open("input.txt").expect("open failed"));

    for c in f.lines().flat_map(|l| l.expect("lines failed").chars()) {
        println!("Character: {}", c);
    }
}
问题是
chars
从字符串中借用,但
l.expect(“行失败”)
仅在闭包中存在,因此编译器给出的错误
借用值的存在时间不够长

3。嵌套用于

此代码

use std::io::{BufRead, BufReader};
use std::fs::File;

pub fn main() {
    let mut f = BufReader::new(File::open("input.txt").expect("open failed"));

    for line in f.lines() {
        for c in line.expect("lines failed").chars() {
            println!("Character: {}", c);
        }
    }
}
工作正常,但它为每行保留一个字符串。此外,如果输入文件上没有换行符,则整个文件将加载到内存中

4
BufRead::一直读到

方法3的一个内存有效的替代方法是使用
Read::Read_直到
,并使用单个字符串读取每一行:

use std::io::{BufRead, BufReader};
use std::fs::File;

pub fn main() {
    let mut f = BufReader::new(File::open("input.txt").expect("open failed"));

    let mut buf = Vec::<u8>::new();
    while f.read_until(b'\n', &mut buf).expect("read_until failed") != 0 {
        // this moves the ownership of the read data to s
        // there is no allocation
        let s = String::from_utf8(buf).expect("from_utf8 failed");
        for c in s.chars() {
            println!("Character: {}", c);
        }
        // this returns the ownership of the read data to buf
        // there is no allocation
        buf = s.into_bytes();
        buf.clear();
    }
}
使用std::io::{BufRead,BufReader};
使用std::fs::File;
pub fn main(){
让mut f=BufReader::new(File::open(“input.txt”).expect(“open failed”);
让mut buf=Vec:::new();
而f.read_until(b'\n',&mut buf).expect(“read_until failed”)!=0{
//这会将读取数据的所有权移动到s
//没有分配
让s=String::from_utf8(buf).expect(“from_utf8失败”);
对于s.chars()中的c{
println!(“字符:{}”,c);
}
//这会将读取数据的所有权返回给buf
//没有分配
buf=s.到_字节();
buf.clear();
}
}
我不能使用
行()
,因为我的文件可能是一行大小为千兆字节的文件。这是从旧版本的Rust复制
Read::chars
的改进。已为您将
.chars()
添加到
BufRead

检查它们的内存,看起来它们一次加载的字节不会超过4个

您的代码看起来将与除锈前相同
Read::chars

use std::io::stdin;
use utf8_chars::BufReadCharsExt;

fn main() {
    for c in stdin().lock().chars().map(|x| x.unwrap()) {
        println!("{}", c);
    }
}
将以下内容添加到Cargo.toml中:

[dependencies]
utf8-chars = "1.0.0"

对于某些类型的文本文件:
f.lines().flat_map(|l | l.chars())
。。。但这并不是一个好的解决方案。您是否考虑过同时复制实现?它只有约100行,这意味着如果
chars
保持原样,您的代码将很容易升级。作为提醒,通常可以将有用的注释移动到答案中,但如果您不是真的添加到内容中,则可能是。抱歉!我下次一定要这么做。我在哪里可以找到旧的Read::chars()实现?现在我已经决定使用这个板条箱: