gpt4 book ai didi

c# - 如何在C#中将巨大的JSON文件转换为xml文件

转载 作者:行者123 更新时间:2023-11-30 22:54:28 31 4
gpt4 key购买 nike

我正在尝试从巨大的JSON文件(2GB)转换为xml文件。我在读取巨大的JSON文件时遇到了一些麻烦。

我一直在研究如何读取巨大的JSON文件。

我找到了这个:

Out of memory exception while loading large json file from disk

How to parse huge JSON file as stream in Json.NET?

Parsing large json file in .NET

看来我在重复我的问题,但我遇到了一些麻烦,这些问题并没有解决。

因此,我需要加载巨大的JSON文件,社区提出了如下建议:

MyObject o;

using (StreamReader sr = new StreamReader("foo.json"))
using (JsonTextReader reader = new JsonTextReader(sr))
{
var serializer = new JsonSerializer();
reader.SupportMultipleContent = true;

while (reader.Read())
{
if (reader.TokenType == JsonToken.StartObject)
{
// Deserialize each object from the stream individually and process it
var o = serializer.Deserialize<MyObject>(reader);

//Do something with the object
}
}
}


因此,我们可以逐个读取对象并反序列化对象。

我会告诉你我的代码

JsonSerializer serializer = new JsonSerializer();

string hugeJson = "hugJSON.json";
using (FileStream s = File.Open(hugeJson , FileMode.Open))
{
using (StreamReader sr = new StreamReader(s))
{
using (JsonReader reader = new JsonTextReader(sr))
{
reader.SupportMultipleContent = true;
while (reader.Read())
{
if (reader.TokenType == JsonToken.StartObject)
{
var jsonObject = serializer.Deserialize(reader);
string xmlString = "";

XmlDocument doc = JsonConvert.DeserializeXmlNode(jsonObject.ToString(), "json");

using (var stringWriter = new StringWriter())
{
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
doc.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
xmlString = stringWriter.GetStringBuilder().ToString();
}
}
}
}
}
}
}




但是当我尝试 doc.WriteTo(xmlTextWriter)时,我得到 Exception of type System.OutOfMemoryException was thrown.

我一直在尝试 BufferedStream。此类允许我管理大文件,但我还有另一个问题。

我正在阅读 byte[]格式。当我转换为字符串时,json被拆分,由于缺少字符,我无法解析为xml文件

例如:

{ foo:[{
foo:something,
foo1:something,
foo2:something
},
{
foo:something,
foo:som


它被切掉了。

有什么方法可以读取巨大的JSON并将其转换为XML,而无需部分加载JSON?或者我可以按部分加载转换,但我不知道该怎么做。

有任何想法吗?

更新:

我一直在尝试这段代码:

 static void Main(string[] args)
{
string json = "";
string pathJson = "foo.json";
//Read file
string temp = "";
using (FileStream fs = new FileStream(pathJson, FileMode.Open))
{
using (BufferedStream bf = new BufferedStream(fs))
{
byte[] array = new byte[70000];
while (bf.Read(array, 0, 70000) != 0)
{

json = Encoding.UTF8.GetString(array);
temp = String.Concat(temp, json);


}
}
}


XmlDocument doc = new XmlDocument();

doc = JsonConvert.DeserializeXmlNode(temp, "json");


using (var stringWriter = new StringWriter())
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
doc.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
xmlString = stringWriter.GetStringBuilder().ToString();
}


File.WriteAllText("outputPath", xmlString);


}


此代码将json文件转换为xml文件。但是当我尝试转换一个大的json文件(2GB)时,我做不到。该过程花费大量时间,并且字符串没有存储所有json的能力。我如何存储它?有什么方法可以在不使用数据类型字符串的情况下进行转换?

更新:
json格式为:

[{
'key':[some things],
'data': [some things],
'data1':[A LOT OF ENTRIES],
'data2':[A LOT OF ENTRIES],
'data3':[some things],
'data4':[some things]
}]

最佳答案

.Net中的内存不足异常可能是由以下几个问题引起的:


分配了太多的总内存。

如果可能发生这种情况,请按照here所述检查是否以64位模式运行。如果不是,请按照here所述以64位模式重建并重新测试。
large object heap上分配过多的对象导致内存碎片。
分配大于.Net object size limit的单个对象。
无法处理非托管内存(此处不适用)。


在您的情况下,您可能试图分配过多的总内存,但肯定要分配三个非常大的对象:内存temp JSON字符串,内存xmlString XML字符串和内存stringWriter

您可以直接通过JSON文件中的流转换构造一个XDocumentXmlDocument,从而大大减少内存占用并完全消除这些对象。然后,使用XDocument.Save()XmlDocument.Save()将文档直接写入XML文件。

为此,您需要分配自己的XmlNodeConverter,然后使用它构造一个JsonSerializer并按Deserialize JSON from a file所示进行反序列化。以下方法可以解决问题:

public static partial class JsonExtensions
{
public static XDocument LoadXNode(string pathJson, string deserializeRootElementName)
{
using (var stream = File.OpenRead(pathJson))
return LoadXNode(stream, deserializeRootElementName);
}

public static XDocument LoadXNode(Stream stream, string deserializeRootElementName)
{
// Let caller dispose the underlying streams.
using (var textReader = new StreamReader(stream, Encoding.UTF8, true, 1024, true))
return LoadXNode(textReader, deserializeRootElementName);
}

public static XDocument LoadXNode(TextReader textReader, string deserializeRootElementName)
{
var settings = new JsonSerializerSettings
{
Converters = { new XmlNodeConverter { DeserializeRootElementName = deserializeRootElementName } },
};
using (var jsonReader = new JsonTextReader(textReader) { CloseInput = false })
return JsonSerializer.CreateDefault(settings).Deserialize<XDocument>(jsonReader);
}

public static void StreamJsonToXml(string pathJson, string pathXml, string deserializeRootElementName, SaveOptions saveOptions = SaveOptions.None)
{
var doc = LoadXNode(pathJson, deserializeRootElementName);
doc.Save(pathXml, saveOptions);
}
}


然后按如下方式使用它们:

JsonExtensions.StreamJsonToXml(pathJson, outputPath, "json");


在这里我使用的是 XDocument而不是 XmlDocument,因为我相信(但没有亲自检查)它使用的内存更少,例如如Ken Lassesen在 Some hard numbers about XmlDocument, XDocument and XmlReader (x86 versus x64)中的报道。

这种方法消除了前面提到的三个大对象,并大大减少了由于问题#2或#3而导致的内存不足的可能性。

演示小提琴 here



如果即使在确保以64位模式运行并使用上述方法直接在文件之间进行流传输后,仍仍用完内存,则可能仅仅是XML太大而无法容纳您的XML。使用 XDocumentXmlDocument的计算机的虚拟内存空间。如果是这样,您将需要采用一种纯流传输解决方案,该解决方案可以在流传输时从JSON即时转换为XML。不幸的是,Json.NET并未立即提供此功能,因此您将需要一个更复杂的解决方案。

那么,您有什么选择呢?


您可以派生自己的版本的 XmlNodeConverter.cs并重写 ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)以直接写入 XmlWriter而不是 IXmlDocument

尽管可能需要花费几天的时间才能完成,但难度似乎超过了单个stackoverflow答案的难度。
您可以使用 JsonReaderWriterFactory返回的阅读器将JSON即时转换为XML,然后将该阅读器直接传递给 XmlWriter.WriteNode(XmlReader)DataContractJsonSerializer在内部使用此工厂返回的读者和作家,但也可以直接使用。
如果您的JSON具有固定的架构(您的问题尚不清楚),那么您将有更多直接的选择。如 Parsing large json file in .NET所示,逐步反序列化为某些c#数据模型,然后将该模型重新序列化为XML,所使用的内存可能比装入某些通用 DOM(如 XDocument)时要少得多。


选项2可以非常简单地实现,如下所示:

using (var stream = File.OpenRead(pathJson))
using (var jsonReader = JsonReaderWriterFactory.CreateJsonReader(stream, XmlDictionaryReaderQuotas.Max))
{
using (var xmlWriter = XmlWriter.Create(outputPath))
{
xmlWriter.WriteNode(jsonReader, true);
}
}


但是,由此生成的XML比 XmlNodeConverter生成的XML要漂亮得多。例如,给定简单的输入JSON



{"Root":[{
"key":["a"],
"data": [1, 2]
}]}


XmlNodeConverter将创建以下XML:



<json>
<Root>
<key>a</key>
<data>1</data>
<data>2</data>
</Root>
</json>


JsonReaderWriterFactory将创建以下内容(为清楚起见,以缩进形式表示):



<root type="object">
<Root type="array">
<item type="object">
<key type="array">
<item type="string">a</item>
</key>
<data type="array">
<item type="number">1</item>
<item type="number">2</item>
</data>
</item>
</Root>
</root>


生成的XML的确切格式可以在 Mapping Between JSON and XML中找到。

但是,一旦有了有效的XML,就会有XML到XML的流转换解决方案,使您可以将生成的XML转换为最终的所需格式,包括:


C# XSLT Transforming Large XML Files Quickly
How to: Perform Streaming Transform of Large XML Documents (C#)
Combining the XmlReader and XmlWriter classes for simple streaming transformations


是否可以采取其他方式?

不幸

JsonReaderWriterFactory.CreateJsonWriter().WriteNode(xmlReader, true);


它实际上不适合将任意XML转换为JSON,因为它仅允许使用 Mapping Between JSON and XML指定的精确模式进行XML转换。

此外,当从任意XML转换为JSON时,存在数组识别问题:JSON具有数组,XML没有数组,仅包含重复元素。要识别重复元素(或名称相同的元素可能不相邻的元素元组)并将其转换为JSON数组,需要缓冲XML输入或JSON输出(或复杂的两遍算法)。 Mapping Between JSON and XML通过要求 type="object"type="array"属性避免了该问题。

关于c# - 如何在C#中将巨大的JSON文件转换为xml文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56260418/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com