C# 如何从大量JSON对象中流式传输每个对象的原始JSON?

C# 如何从大量JSON对象中流式传输每个对象的原始JSON?,c#,.net,json,json.net,C#,.net,Json,Json.net,请注意,这不是一个重复的问题,因为这是一个关于逐个对象解析(而不是反序列化)大型数组对象并检索原始JSON的问题 我正在处理非常大的JSON有效负载数组(数十GB) 每个对象的结构可能不同,即异构: [ {"id": "foo", "value": "bar"}, {"key": "foo", "name": "bar", "age": 10}, ... ] 我如何处理每个对象的流,并检索每个对象的原始JSON字符串 我目前的解决方案是使用StreamReader和Js

请注意,这不是一个重复的问题,因为这是一个关于逐个对象解析(而不是反序列化)大型数组对象并检索原始JSON的问题

我正在处理非常大的JSON有效负载数组(数十GB)

每个对象的结构可能不同,即异构:

[
    {"id": "foo", "value": "bar"},
    {"key": "foo", "name": "bar", "age": 10},
    ...
]
我如何处理每个对象的流,并检索每个对象的原始JSON字符串

我目前的解决方案是使用
StreamReader
JsonTextReader
使用
JObject
反序列化每个对象,然后使用
.ToString()
检索JSON。但我更愿意避免性能成本和GC分配压力,因为必须从JSON反序列化才能再次检索JSON

var file = new FileInfo(@"C:\Very.Large.Array.json");

using (var sr = new StreamReader(file.OpenRead()))
using (var reader = new JsonTextReader(sr))
{
  while (reader.Read())
  {
    if (reader.TokenType == JsonToken.StartObject)
    {
      var obj = JObject.Load(reader);      
      var rawJSON = obj.ToString();
    }
  }
}

我认为您应该使用
JsonTextWriter
以及
JsonTextReader
。下面是演示该思想的简单POC类

我想,要使这段代码达到生产质量,还需要一些改进。与此类似,您可以将
StringBuilder sb
从局部变量提升到实例字段,并在每次迭代时清除它,而不是创建新对象

但我的目标只是展示基本理念

public class JsonBigFileReader
{
    static string ReadSingleObject(JsonTextReader reader)
    {
        StringBuilder sb = new StringBuilder();

        using (var sw = new StringWriter(sb))
        {
            using (var writer = new JsonTextWriter(sw))
            {
                writer.WriteToken(reader, true);    //  writes current token including its children (meaning the whole object)
            }
        }
        return sb.ToString();
    }

    public IEnumerable<string> ReadArray(string fileName)
    {
        var file = new FileInfo(fileName);
        using (var sr = new StreamReader(file.OpenRead()))
        using (var reader = new JsonTextReader(sr))
        {
            reader.Read();
            while (reader.Read())
            {
                if (reader.TokenType == JsonToken.StartObject)
                {
                    yield return ReadSingleObject(reader);
                }
            }
        }
    }
}
公共类JsonBigFileReader
{
静态字符串ReadSingleObject(JsonTextReader阅读器)
{
StringBuilder sb=新的StringBuilder();
使用(var sw=新的StringWriter(sb))
{
使用(var writer=newjsontextwriter(sw))
{
WriteToken(reader,true);//写入当前标记,包括其子标记(表示整个对象)
}
}
使某人返回字符串();
}
公共IEnumerable可读数组(字符串文件名)
{
var file=新文件信息(文件名);
使用(var sr=newstreamreader(file.OpenRead()))
使用(var reader=newjsontextreader(sr))
{
reader.Read();
while(reader.Read())
{
if(reader.TokenType==JsonToken.StartObject)
{
产生返回ReadSingleObject(reader);
}
}
}
}
}

我认为您应该使用
JsonTextWriter
以及
JsonTextReader
。下面是演示该思想的简单POC类

我想,要使这段代码达到生产质量,还需要一些改进。与此类似,您可以将
StringBuilder sb
从局部变量提升到实例字段,并在每次迭代时清除它,而不是创建新对象

但我的目标只是展示基本理念

public class JsonBigFileReader
{
    static string ReadSingleObject(JsonTextReader reader)
    {
        StringBuilder sb = new StringBuilder();

        using (var sw = new StringWriter(sb))
        {
            using (var writer = new JsonTextWriter(sw))
            {
                writer.WriteToken(reader, true);    //  writes current token including its children (meaning the whole object)
            }
        }
        return sb.ToString();
    }

    public IEnumerable<string> ReadArray(string fileName)
    {
        var file = new FileInfo(fileName);
        using (var sr = new StreamReader(file.OpenRead()))
        using (var reader = new JsonTextReader(sr))
        {
            reader.Read();
            while (reader.Read())
            {
                if (reader.TokenType == JsonToken.StartObject)
                {
                    yield return ReadSingleObject(reader);
                }
            }
        }
    }
}
公共类JsonBigFileReader
{
静态字符串ReadSingleObject(JsonTextReader阅读器)
{
StringBuilder sb=新的StringBuilder();
使用(var sw=新的StringWriter(sb))
{
使用(var writer=newjsontextwriter(sw))
{
WriteToken(reader,true);//写入当前标记,包括其子标记(表示整个对象)
}
}
使某人返回字符串();
}
公共IEnumerable可读数组(字符串文件名)
{
var file=新文件信息(文件名);
使用(var sr=newstreamreader(file.OpenRead()))
使用(var reader=newjsontextreader(sr))
{
reader.Read();
while(reader.Read())
{
if(reader.TokenType==JsonToken.StartObject)
{
产生返回ReadSingleObject(reader);
}
}
}
}
}

将返回类型更改为IEnumerablet这并不能回答我的问题,我正在寻找一种不必将JSON反序列化为对象的方法。我的问题不是收益率回归,这就是为什么它是一个评论。答案是更改您的文件。假设文件以任何方式格式化是否安全?像每行一个对象?否则,您必须使用每个字符的JSON字符来匹配大括号来查找对象。它可以缩进,也可以不缩进,因此我猜必须解析JSON。将返回类型更改为IEnumerableth这并不能回答我的问题,我正在寻找一种不必将JSON反序列化为对象的方法。我的问题不是收益率回归,这就是为什么它是一个评论。答案是更改您的文件。假设文件以任何方式格式化是否安全?像每行一个对象?否则,您将不得不使用每个字符的JSON字符,以匹配大括号来查找对象。它可以缩进,也可以不缩进,因此我猜必须解析JSON。