反序列化json数组stream一次一个项目
我将一个大对象的数组序列化为一个json http响应stream。 现在我想从这个stream反序列化这些对象。 有没有任何C#库,可以让我这样做? 我看了json.net,但似乎我不得不反序列化一次完整的数组对象。
[{large json object},{large json object}.....]
澄清:我想一次从stream中读取一个json对象并将其反序列化。
为了以增量方式读取JSON,您需要将JsonTextReader
与StreamReader
结合使用。 但是,您不一定必须从阅读器手动读取所有JSON。 您应该能够利用Linq-To-JSON API从读取器加载每个大对象,以便您可以更轻松地使用它。
举一个简单的例子,说我有一个JSON文件,看起来像这样:
[ { "name": "foo", "id": 1 }, { "name": "bar", "id": 2 }, { "name": "baz", "id": 3 } ]
从文件中递增读取的代码可能如下所示。 (在你的情况下,你会用你的响应stream来replaceFileStream。)
using (FileStream fs = new FileStream(@"C:\temp\data.json", FileMode.Open, FileAccess.Read)) using (StreamReader sr = new StreamReader(fs)) using (JsonTextReader reader = new JsonTextReader(sr)) { while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { // Load each object from the stream and do something with it JObject obj = JObject.Load(reader); Console.WriteLine(obj["id"] + " - " + obj["name"]); } } }
上面的输出看起来像这样:
1 - foo 2 - bar 3 - baz
我简化了parsing器/解串器的一个样本/testing,以更直接地回答这个问题的用例。
这里是testing数据:
https://github.com/ysharplanguage/FastJsonParser/tree/master/JsonTest/TestData
(参见fathers.json.txt)
这里是示例代码:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; // Our stuff using System.Text.Json; //... public class FathersData { public Father[] fathers { get; set; } } public class Someone { public string name { get; set; } } public class Father : Someone { public int id { get; set; } public bool married { get; set; } // Lists... public List<Son> sons { get; set; } // ... or arrays for collections, that's fine: public Daughter[] daughters { get; set; } } public class Child : Someone { public int age { get; set; } } public class Son : Child { } public class Daughter : Child { public string maidenName { get; set; } } //... static void FilteredFatherStreamTestSimplified() { // Get our parser: var parser = new JsonParser(); // (Note this will be invoked thanks to the "filters" dictionary below) Func<object, object> filteredFatherStreamCallback = obj => { Father father = (obj as Father); // Output only the individual fathers that the filters decided to keep (ie, when obj.Type equals typeof(Father)), // but don't output (even once) the resulting array (ie, when obj.Type equals typeof(Father[])): if (father != null) { Console.WriteLine("\t\tId : {0}\t\tName : {1}", father.id, father.name); } // Do not project the filtered data in any specific way otherwise, // just return it deserialized as-is: return obj; }; // Prepare our filter, and thus: // 1) we want only the last five (5) fathers (array index in the resulting "Father[]" >= 29,995), // (assuming we somehow have prior knowledge that the total count is 30,000) // and for each of them, // 2) we're interested in deserializing them with only their "id" and "name" properties var filters = new Dictionary<Type, Func<Type, object, object, int, Func<object, object>>> { // We don't care about anything but these 2 properties: { typeof(Father), // Note the type (type, obj, key, index) => ((key as string) == "id" || (key as string) == "name") ? filteredFatherStreamCallback : JsonParser.Skip }, // We want to pick only the last 5 fathers from the source: { typeof(Father[]), // Note the type (type, obj, key, index) => (index >= 29995) ? filteredFatherStreamCallback : JsonParser.Skip } }; // Read, parse, and deserialize fathers.json.txt in a streamed fashion, // and using the above filters, along with the callback we've set up: using (var reader = new System.IO.StreamReader(FATHERS_TEST_FILE_PATH)) { FathersData data = parser.Parse<FathersData>(reader, filters); System.Diagnostics.Debug.Assert ( (data != null) && (data.fathers != null) && (data.fathers.Length == 5) ); foreach (var i in Enumerable.Range(29995, 5)) System.Diagnostics.Debug.Assert ( (data.fathers[i - 29995].id == i) && !String.IsNullOrEmpty(data.fathers[i - 29995].name) ); } Console.ReadKey(); }
其余的位在这里可用:
https://github.com/ysharplanguage/FastJsonParser
“HTH,
这是我的解决scheme(来自不同来源,但主要基于Brian Rogers解决scheme)将大型JSON文件(这是一个对象数组)转换为任何通用对象的XML文件。
JSON看起来像这样:
{ "Order": [ { order object 1}, { order object 2}, {...} { order object 10000}, ] }
输出XML:
<Order>...</Order> <Order>...</Order> <Order>...</Order>
C#代码:
XmlWriterSettings xws = new XmlWriterSettings { OmitXmlDeclaration = true }; using (StreamWriter sw = new StreamWriter(xmlFile)) using (FileStream fs = new FileStream(jsonFile, FileMode.Open, FileAccess.Read)) using (StreamReader sr = new StreamReader(fs)) using (JsonTextReader reader = new JsonTextReader(sr)) { //sw.Write("<root>"); while (reader.Read()) { if (reader.TokenType == JsonToken.StartArray) { while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { JObject obj = JObject.Load(reader); XmlDocument doc = JsonConvert.DeserializeXmlNode(obj.ToString(), "Order"); sw.Write(doc.InnerXml); // a line of XML code <Order>...</Order> sw.Write("\n"); //this approach produces not strictly valid XML document //add root element at the beginning and at the end to make it valid XML } } } } //sw.Write("</root>"); }