所以,我试图在一个比可用RAM大的gz压缩文件上执行一种面向行的操作,所以首先将其阅读到字符串中是被排除的。问题是,如何在rust(短于gunzip file.gz|./my-rust-program
)中做到这一点?
我目前的解决方案基于flate2
和一堆缓冲读取器:
use std::path::Path;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use flate2::bufread::GzDecoder as BufGzDecoder;
fn main() {
let mut fname = "path_to_a_big_file.gz";
let f = File::open(fname).expect("Ooops.");
let bf = BufReader::new(f); // Here's the first reader so I can plug data into BufGzDecoder.
let br = BufGzDecoder::new(bf); // Yep, here. But, oops, BufGzDecoder has not lines method,
// so try to stick it into a std BufReader.
let bf2 = BufReader::new(br); // What!? This works!? Yes it does.
// After a long time ...
eprintln!("count: {}",bf2.lines().count());
// ... the line count is here.
}
字符串
为了把上面的话,我注意到我不能直接插入一个文件到flate2::bufread::GzDecoder
,所以我首先创建了std::io::BufReader
示例,它与前者的构造函数方法兼容。但是,我没有看到任何有用的迭代器与flate2::bufread::GzDecoder
相关,所以我在它上面构建了另一个std::io::BufReader
。令人惊讶的是,这起作用了。我得到了我的Lines
迭代器,它在我的机器上仅用了一分钟多的时间就读取了整个文件,但感觉它过于冗长,不优雅,而且可能效率低下(更担心这一部分)。
2条答案
按热度按时间xxhby3vn1#
问题中描述的每个“缓冲诱导”步骤在这里都是必要的。
1.然后,第二个
BufReader
将用于识别行分隔模式,并准确地返回完整的文本行。然而,对于第一个有一个快捷方式,
flate2
crate提供了read::GzDecoder
,它接受一个常规的读取器,并自动在其上使用缓冲阅读。字符串
这样做之后,推荐的提高效率的方法是确保程序是用正确的配置文件(release 模式)构建的,并通过使用
read_line
而不是lines()
迭代器来为每行重用相同的String值,从而减少内存分配的数量。另请参阅:
kgqe7b3p2#
有些gzip文件可能有多个成员,请参阅flate2文档。在这种情况下,行迭代器将只遍历第一个结果并意外停止(参见示例here)。您可能需要使用
MultiGzDecoder
来避免该问题:字符串