C# 行分隔json序列化和反序列化

C# 行分隔json序列化和反序列化,c#,json.net,C#,Json.net,我使用的是JSON.NET和C#5。我需要将对象列表序列化/反序列化为行分隔的json。例如 {"some":"thing1"} {"some":"thing2"} {"some":"thing3"} 及 为什么我需要,因为它需要Google BigQuery 更新:我发现的一种方法是将每个对象分别序列化,并在末尾加入新行。您可以通过使用JsonTextReader手动解析JSON,并将SupportMultipleContent标记设置为true来完成此操作 如果我们看一下您的第一个示例,并

我使用的是JSON.NET和C#5。我需要将对象列表序列化/反序列化为行分隔的json。例如

{"some":"thing1"}
{"some":"thing2"}
{"some":"thing3"}

为什么我需要,因为它需要Google BigQuery


更新:我发现的一种方法是将每个对象分别序列化,并在末尾加入新行。

您可以通过使用
JsonTextReader
手动解析JSON,并将
SupportMultipleContent
标记设置为
true
来完成此操作

如果我们看一下您的第一个示例,并创建一个名为
Foo
的POCO:

public class Foo
{
    [JsonProperty("some")]
    public string Some { get; set; }
}
我们就是这样分析它的:

var json = "{\"some\":\"thing1\"}\r\n{\"some\":\"thing2\"}\r\n{\"some\":\"thing3\"}";
var jsonReader = new JsonTextReader(new StringReader(json))
{
    SupportMultipleContent = true // This is important!
};

var jsonSerializer = new JsonSerializer();
while (jsonReader.Read())
{
    Foo foo = jsonSerializer.Deserialize<Foo>(jsonReader);
}
注意:对于Json.Net 10.0.4和更高版本,相同的代码也支持逗号分隔的Json条目(请参见)

要使用.Net 5(C#9)和
System.Text.Json.JsonSerializer
类实现,对于“大”数据,我编写了流处理代码

使用
System.IO.Pipelines
扩展包,这是非常有效的

使用系统;
使用系统缓冲区;
使用System.Collections.Generic;
使用System.IO;
使用系统IO管道;
使用系统文本;
使用System.Text.Json;
使用System.Threading.Tasks;
班级计划
{
静态只读字节[]NewLineChars={(字节)'\r',(字节)'\n'};
静态只读字节[]空白字符={(字节)'\r',(字节)'\n',(字节)'',(字节)'\t'};
专用静态异步任务Main()
{
JsonSerializerOptions=new(JsonSerializerDefaults.Web);
var json=“{\'some\':\'thing1\'}\r\n{\'some\':\'thing2\'}\r\n{\'some\':\'thing3\'”;
var contentStream=newmemorystream(Encoding.UTF8.GetBytes(json));
var pipeReader=pipeReader.Create(contentStream);
等待foreach(ReadItemsAsync(pipeReader,jsonOptions)中的var foo)
{
WriteLine($“foo:{foo.Some}”);
}
}
静态异步IAsyncEnumerable ReadItemsAsync(PipeReader PipeReader,JsonSerializerOptions jsonOptions=null)
{
while(true)
{
var result=await pipeReader.ReadAsync();
var buffer=result.buffer;
bool isCompleted=result.isCompleted;
SequencePosition bufferPosition=buffer.Start;
while(true)
{
var(值,高级顺序)=TryReadNextItem(缓冲区,参考缓冲区位置,已完成,jsonOptions);
if(值!=null)
{
收益回报值;
}
if(高级顺序)
{
pipeReader.AdvanceTo(bufferPosition,buffer.End);//推进我们在管道中的位置
打破
}
}
如果(已完成)
屈服断裂;
}
}
静态(TValue,bool)TryReadNextItem(只读序列,参考序列位置,bool已完成,JSONSerializedProptions jsonOptions)
{
var reader=新的SequenceReader(sequence.Slice(sequencePosition));
while(!reader.End)//循环直到结束或读取一项
{
if(reader.TryReadToAny(out ReadOnlySpan itemBytes、NewLineChars、AdvanceCastDelimiter:true))
{
sequencePosition=读卡器位置;
if(itemBytes.TrimStart(WhiteSpaceChars.IsEmpty)
{
继续;
}
返回(JsonSerializer.Deserialize(itemBytes,jsonOptions),false);
}
否则,如果(已完成)
{
//阅读最后一项
var remainingReader=sequence.Slice(reader.Position);
使用var memoryOwner=MemoryPool.Shared.Rent((int)reader.Remaining);
remainingReader.CopyTo(memoryOwner.Memory.Span);
reader.Advance(remainingReader.Length);//将reader提前到末尾
sequencePosition=读卡器位置;
if(!itemBytes.TrimStart(WhiteSpaceChars.IsEmpty)
{
返回(JsonSerializer.Deserialize(memoryOwner.Memory.Span,jsonOptions),true);
}
其他的
{
返回值(默认值,true);
}
}
其他的
{
//序列中没有其他项目
打破
}
}
//PipeReader需要阅读更多内容
返回值(默认值,true);
}
}
公开课Foo
{
公共字符串
{
得到;
设置
}
}

运行在

如何序列化?不使用字符串生成器,因为这对于大量数据来说速度很慢。@shadowsora要序列化,只需将每个元素作为JSON写入/序列化到文件中,并根据需要在每个元素之后写入分隔符。有关详细信息,请参阅。
var json = "{\"some\":\"thing1\"}\r\n{\"some\":\"thing2\"}\r\n{\"some\":\"thing3\"}";
var jsonReader = new JsonTextReader(new StringReader(json))
{
    SupportMultipleContent = true // This is important!
};

var jsonSerializer = new JsonSerializer();
while (jsonReader.Read())
{
    Foo foo = jsonSerializer.Deserialize<Foo>(jsonReader);
}
listOfFoo.Add(jsonSerializer.Deserialize<Foo>(jsonReader));