【问题标题】:How can I read a non-UTF8 file line by line in Rust如何在 Rust 中逐行读取非 UTF8 文件
【发布时间】:2020-09-24 06:43:15
【问题描述】:

我正在尝试在 Rust 中一次读取一行文件,并按照this question 中的建议开始:

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

fn main() -> Result<(), Box<dyn Error>> {
    let file = File::open("countries.txt")?;
    let reader = BufReader::new(file);
    for line in reader.lines() {
        match line {
            Ok(line) => println!("Ok: {}", line),
            Err(error) => println!("Err: {}", error),
        }
    }
    return Ok(());
}

但是,我有非 UTF8 文件。 Python chardet.universaldetector 库告诉我这是 ISO-8859-1:

Cuba
Curaçao
Cyprus
Czech Republic
Côte d'Ivoire

开箱即用,Rust 无法解释非 UTF8 字符的行:

$ ./target/release/main1 
Ok: Cuba
Err: stream did not contain valid UTF-8
Ok: Cyprus
Ok: Czech Republic
Err: stream did not contain valid UTF-8

所以我尝试了encoding_rs_io 库。我在这里使用的是 Windows 1252 而不是 ISO-8859-1,但它似乎适用于这些数据:

use std::error::Error;
use std::fs::File;
use std::io::Read;

use encoding_rs::WINDOWS_1252;
use encoding_rs_io::DecodeReaderBytesBuilder;

fn main() -> Result<(), Box<dyn Error>> {
    let file = File::open("countries.txt")?;
    let mut reader = DecodeReaderBytesBuilder::new().encoding(Some(WINDOWS_1252)).build(file);
    let mut buffer = vec![];
    reader.read_to_end(&mut buffer)?;
    println!("{}", String::from_utf8(buffer).unwrap());
    return Ok(());
}

这样就成功读取了UTF8字符:

$ ./target/release/main2 
Cuba
Curaçao
Cyprus
Czech Republic
Côte d'Ivoire

但是,它没有lines() 方法,因此不能一次读取一行。我注意到ripgrep 项目使用这个库来解码非UTF8 文件,并且我已经在调试器中进入了它的源代码。据我所知,它正在做自己的手动 CR/LF 检测。

所以,在 Rust 中一次一行读取非 UTF8 文件的任务肯定已经解决了。我真的需要重新发明轮子吗?非常感谢您的帮助!

【问题讨论】:

标签: utf-8 rust


【解决方案1】:

DecodeReaderBytesimplements io::Read,因此您应该能够将其包装在std::io::BufReader 中并使用其lines 方法:

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

use encoding_rs::WINDOWS_1252;
use encoding_rs_io::DecodeReaderBytesBuilder;

fn main() -> Result<(), Box<dyn Error>> {
    let file = File::open("countries.txt")?;
    let mut reader = BufReader::new(
        DecodeReaderBytesBuilder::new()
            .encoding(Some(WINDOWS_1252))
            .build(file));
    for line in reader.lines() {
        println!("{}", line);
    }
    return Ok(());
}

【讨论】:

    猜你喜欢
    • 2020-10-24
    • 1970-01-01
    • 2018-02-03
    • 1970-01-01
    • 2011-11-02
    • 2020-01-29
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多