You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中用Serde流式解析超大JSON数组(无需全量加载)

在Rust中使用Serde流式解析超大JSON数组

当面对GB级别的JSON文档,仅需提取其中某个大型数组内的对象时,流式解析是唯一可行的方案——它无需将整个文档加载到内存,而是逐段读取、处理后立即丢弃,内存占用始终保持在可控范围。以下是基于Serde生态的具体实现步骤:

1. 添加依赖

在Cargo.toml中引入必要的 crate:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# 若需处理网络流,可额外添加reqwest
# reqwest = { version = "0.11", features = ["stream"] }

2. 定义目标结构体

先定义数组内对象对应的Rust结构体,让Serde自动完成反序列化映射:

use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] // 匹配JSON字段命名,非驼峰结构可移除
struct Feature {
    r#type: String,
    // 根据实际JSON结构补充字段,例:
    // geometry: Geometry,
    // properties: HashMap<String, serde_json::Value>,
}

3. 实现流式解析逻辑

核心思路是利用serde_json::Deserializer的流式能力,跳过外层无关内容,仅遍历并处理features数组的元素:

use serde::de::{DeserializeSeed, MapAccess, SeqAccess, Visitor};
use serde_json::{self, Deserializer};
use std::fmt;
use std::fs::File;
use std::io::Read;

// 自定义Visitor,用于定位并处理features数组
struct FeaturesVisitor;

impl<'de> Visitor<'de> for FeaturesVisitor {
    type Value = ();

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("FeatureCollection类型的JSON对象,包含features数组")
    }

    fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        while let Some(key) = map.next_key::<String>()? {
            if key == "features" {
                // 找到features字段,开始遍历数组元素
                let mut seq = map.next_value::<serde_json::de::SeqAccess<'de>>()?;
                while let Some(feature) = seq.next_element::<Feature>()? {
                    // 在这里处理单个Feature对象,例如写入数据库、数据分析等
                    println!("处理Feature: {:?}", feature);
                }
                break;
            } else {
                // 跳过外层其他无关字段,不占用额外内存
                map.next_value::<serde_json::Value>()?;
            }
        }
        Ok(())
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 示例:从本地文件读取,可替换为网络流(如reqwest的Response)
    let file = File::open("large_feature_collection.json")?;

    // 创建流式反序列化器,支持任意实现Read trait的输入源
    let deserializer = Deserializer::from_reader(file);
    let mut deserializer = deserializer.into_iter::<serde_json::Value>();

    // 用自定义Visitor定位并处理features数组
    deserializer.deserialize_any(FeaturesVisitor)?;

    Ok(())
}

关键细节说明

  • 流式输入适配:Deserializer::from_reader支持所有实现Read trait的对象,包括本地文件、TCP流、reqwest响应流等,数据会被逐段读取处理。
  • 内存控制:每次仅在内存中保留一个Feature对象,处理完成后即可释放,内存占用稳定在单个对象的大小。
  • 跳过无关内容:自定义Visitor会遍历外层对象的键值对,仅处理features字段,其他字段直接跳过,避免不必要的内存消耗。

扩展场景处理

如果JSON文档是压缩格式(如gzip),可通过flate2 crate添加解码层:

// 添加依赖:flate2 = "1.0"
use flate2::read::GzDecoder;

// 将文件读取替换为gzip解码流
let file = File::open("large_data.json.gz")?;
let decoder = GzDecoder::new(file);
let deserializer = Deserializer::from_reader(decoder);

内容的提问来源于stack exchange,提问作者Michel Krämer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 22:38:26