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

如何反序列化50GB大型复杂JSON文件?附压缩包处理代码问题

问题描述

我有一个约50GB的JSON文件需要反序列化,该文件包含14个数组,已编写对应15个类的POCO文件(含根类)。尝试不解压完整压缩包直接处理数据,使用IO.Compression编写了C#代码,但代码在任务的foreach循环中失败,报错System.Threading.Tasks.VoidTaskResult。

代码如下:

using System.IO.Compression;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace read_and_parse
{
    internal class Program
    {
        static void Main() 
        {
            var fc = new Program();

            string zip_path = @"C:\Projects\BBR\Download_Total\example_json.zip";
            using FileStream file = File.OpenRead(zip_path);
            using (var zip = new ZipArchive(file, ZipArchiveMode.Read))
            {
                foreach (ZipArchiveEntry entry in zip.Entries)
                {

                    string[] name_split = entry.Name.Split('_');
                    string name = name_split.Last().Substring(0, name_split.Last().Length - 5);
                    bool canConvert = long.TryParse(name, out long number1);
                    if (canConvert == true)
                    {
                        Task task = fc.ParseJsonFromZippedFile(entry);
                    }
                }
            }
        }

        private async Task ParseJsonFromZippedFile(ZipArchiveEntry entry)
        {
            JsonSerializerOptions options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
            await using Stream entryStream = entry.Open();

            IAsyncEnumerable<JsonNode?> enumerable = JsonSerializer.DeserializeAsyncEnumerable<JsonNode>(entryStream, options);
            await foreach (JsonNode? obj in enumerable) 
            {
                // Parse only subset of the object
                JsonNode? bbrSagNode = obj?["BBRSaglist"];
                if (bbrSagNode is null) continue;
                else
                {
                    var bbrSag = bbrSagNode.Deserialize<BBRSagList>();                    
                }
            }

        }

    }
}
解决方案

1. 修复异步方法调用问题

Main方法中调用ParseJsonFromZippedFile时仅创建Task但未等待,导致程序可能在异步任务执行前就释放了ZipArchive等资源,引发错误。需将Main改为异步方法并等待任务:

static async Task Main() 
{
    var fc = new Program();

    string zip_path = @"C:\Projects\BBR\Download_Total\example_json.zip";
    using FileStream file = File.OpenRead(zip_path);
    using (var zip = new ZipArchive(file, ZipArchiveMode.Read))
    {
        foreach (ZipArchiveEntry entry in zip.Entries)
        {
            string[] name_split = entry.Name.Split('_');
            string name = name_split.Last().Substring(0, name_split.Last().Length - 5);
            if (long.TryParse(name, out _))
            {
                await fc.ParseJsonFromZippedFile(entry);
            }
        }
    }
}

2. 修正流式反序列化逻辑

DeserializeAsyncEnumerable<T>适用于多行JSON(每行一个独立JSON对象),但你的JSON是单个根对象结构,直接使用会导致解析失败。应直接反序列化到根POCO类,再按需处理目标数组:

假设根类名为RootObject,修改ParseJsonFromZippedFile方法:

private async Task ParseJsonFromZippedFile(ZipArchiveEntry entry)
{
    JsonSerializerOptions options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
    await using Stream entryStream = entry.Open();

    // 直接反序列化到根类
    var root = await JsonSerializer.DeserializeAsync<RootObject>(entryStream, options);
    
    if (root?.BBRSaglist != null)
    {
        // 处理BBRSaglist数组,可按需分批处理避免内存溢出
        foreach (var item in root.BBRSaglist)
        {
            // 处理单个BBRSag项
        }
    }
}

3. 大文件内存优化(可选)

若根对象直接反序列化占用内存过高,可使用Utf8JsonReader进行低内存流式解析,仅提取BBRSaglist数组内容:

private async Task ParseJsonFromZippedFile(ZipArchiveEntry entry)
{
    JsonSerializerOptions options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
    await using Stream entryStream = entry.Open();
    using var jsonReader = new Utf8JsonReader(new StreamReader(entryStream).BaseStream, leaveOpen: true);

    while (jsonReader.Read())
    {
        // 定位到BBRSaglist数组的起始位置
        if (jsonReader.TokenType == JsonTokenType.PropertyName && jsonReader.GetString() == "BBRSaglist")
        {
            jsonReader.Read(); // 跳过属性名,进入数组节点
            if (jsonReader.TokenType == JsonTokenType.StartArray)
            {
                // 逐个解析数组元素
                while (jsonReader.Read())
                {
                    if (jsonReader.TokenType == JsonTokenType.EndArray)
                        break;
                    
                    var sagItem = JsonSerializer.Deserialize<BBRSag>(ref jsonReader, options);
                    // 处理单个sagItem
                }
            }
            break; // 找到目标数组后停止遍历其他属性
        }
    }
}

内容的提问来源于stack exchange,提问作者TomGeo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:27:42