在 rust 中加载大型 json 文件(100GB+)[关闭]

问题描述 投票:0回答:1

我希望加载超过 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 rust etl large-data large-files
1个回答
2
投票

首先,如果你接受正常的完整 JSON,你的问题真的很难。

所以我假设如下:

  • 您的文件总是以
    [
    .
  • 开头
  • 然后,后面跟着任意数量的有效 JSON 字符串,由
    ,
    分隔。
  • 在 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")}
© www.soinside.com 2019 - 2024. All rights reserved.