我希望加载超过 100GB+ 的大型 json 文件。此文件中的对象不是静态的,而且几乎从不相同。我发现这个箱子叫做 nop-json https://crates.io/crates/nop-json/2.0.5。但我无法以我想要的方式将其投入工作。这是我目前的解决方案,但感觉有点像作弊。
let file = File::open("./file.json")?;
let reader = BufReader::new(file);
for line in reader.lines() {
//code
}
我正在像阅读文本文件一样阅读文件并以这种方式进行迭代。问题是,通过这个解决方案,我将它作为一个字符串读取,并将整个文件加载到内存中。
我是生锈的新手,所以我正在寻求有关此问题的帮助。我在 python 中有一个成功的实现,它工作得很好,但它太慢了。
编辑:
感谢您到目前为止的回复,这里有更多信息:
我的 *.json 文件有 1 个包含数百万个对象的数组。例子:
[
{
"foo": "bar",
"bar": "foor"
},
{
"foo": "bar",
"bar": "foor"
},
{
"foo": "bar",
"bar": "foor"
},
{
"foo": "bar",
"bar": "foor"
}
]
等..
以这种方式将文件作为文本文件读取的问题是,并非每个对象都恰好是 1 行。一个对象的行数是不一样的
一些可能的解决方案可能是读取一大块文件,然后通过类似于模式
}, {
的东西检查 json 对象在哪里结束。但这似乎不够熟练。
首先,如果你接受正常的完整 JSON,你的问题真的很难。
所以我假设如下:
[
.,
分隔。]
.意思是,我们现在有一堆可流式传输的独立 JSON 对象,它们包裹在我们自己的数组表示中。
有了它,我们可以利用
serde_json
和一点胶水按值解析文件值:
use std::error::Error;
use std::io::Read;
use serde_json::{Deserializer, Value};
const JSON_FILE: &[u8] = br#"[
{
"foo": "bar",
"bar": "foor"
},
{
"foo": "bar",
"bar": "foor"
},
{
"foo": "bar",
"bar": "foor"
},
{
"foo": "bar",
"bar": "foor"
}
]"#;
fn open_file() -> impl Read {
JSON_FILE
}
fn take_json_value(input_stream: &mut dyn Read) -> Result<Value, Box<dyn Error>> {
Ok(Deserializer::from_reader(input_stream)
.into_iter()
.next()
.ok_or("Expected a JSON value!")??)
}
fn main() {
// Is of type `impl Read`, and can only be read once.
// (To reproduce the situation of reading a file)
let mut input_stream = open_file();
// Skip initial `[`
let mut skipped = 0u8;
input_stream
.read_exact(std::slice::from_mut(&mut skipped))
.unwrap();
assert_eq!(skipped, b'[');
loop {
let value = take_json_value(&mut input_stream).unwrap();
println!("- {}", value);
// Skip `,` after the value
input_stream
.read_exact(std::slice::from_mut(&mut skipped))
.unwrap();
if skipped != b',' {
break;
}
}
// Verify that the ending `]` exists
let mut leftover_data = vec![b'[', skipped];
input_stream.read_to_end(&mut leftover_data).unwrap();
serde_json::from_slice::<[u8; 0]>(&leftover_data).unwrap();
}
- Object {"bar": String("foor"), "foo": String("bar")}
- Object {"bar": String("foor"), "foo": String("bar")}
- Object {"bar": String("foor"), "foo": String("bar")}
- Object {"bar": String("foor"), "foo": String("bar")}