【发布时间】:2020-11-06 08:59:21
【问题描述】:
我正在使用 C# 动态功能来反序列化 Json。它非常适合小文件。但是,如果数据文件变大(我正在使用 500mb 文件进行测试),反序列化器将抛出如下所示的内存异常。
>Message: Exception of type 'System.OutOfMemoryException' was thrown.
>Source: mscorlib. StackTrace: at System.String.CtorCharArrayStartLength(Char[] value, Int32 startIndex, Int32 length)
at Newtonsoft.Json.Utilities.StringReference.ToString()
at Newtonsoft.Json.JsonTextReader.ParseReadNumber(ReadType readType, Char firstChar, Int32 initialPosition)
at Newtonsoft.Json.JsonTextReader.ParseNumber(ReadType readType)
at Newtonsoft.Json.JsonTextReader.ParseValue()
at Newtonsoft.Json.JsonTextReader.Read()
at Newtonsoft.Json.JsonWriter.WriteToken(JsonReader reader, Boolean writeChildren, Boolean writeDateConstructorAsDate, Boolean writeComments)
at Newtonsoft.Json.Linq.JTokenWriter.WriteToken(JsonReader reader, Boolean writeChildren, Boolean writeDateConstructorAsDate, Boolean writeComments)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateJObject(JsonReader reader)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
at ShapeFile.Program.Main(String[] args) in C:\Users\HP\source\repos\ShapeFile\Program.cs:line 21
在任务管理器中,我可以看到内存消耗确实快速增长,直到它完全利用到我本地电脑的 16GB。 任何想法为什么会这样?
示例代码:
string jsonFile = @"D:\3D Map\Road\Road_3.geojson";
var myJsonResponse = File.ReadAllText(jsonFile);
dynamic myDeserializedClass = JsonConvert.DeserializeObject<dynamic>(myJsonResponse);
我认为这个问题可能是由于内存中有这么大的字符串,但无论如何我仍然需要动态读取这个 json 文件而不是创建一些类(实际上可以工作)以反序列化 JSON到 .NET 对象中。我不想创建类的原因是因为不同的json文件有不同的文件规格。
如果无法动态读取整个大型 json 文件,是否可以只读取示例 json 文件中的 Feature 和 Properties2 而无需为这两个文件创建类?下面还有示例类。
class Class1
{
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Properties
{
public string name { get; set; }
}
public class Crs
{
public string type { get; set; }
public Properties properties { get; set; }
}
public class Properties2
{
public int ID_0 { get; set; }
public string ISO { get; set; }
public string NAME_0 { get; set; }
public int ID_1 { get; set; }
public string NAME_1 { get; set; }
public int ID_2 { get; set; }
public string NAME_2 { get; set; }
public string TYPE_2 { get; set; }
public string ENGTYPE_2 { get; set; }
public object NL_NAME_2 { get; set; }
public string VARNAME_2 { get; set; }
}
public class Geometry
{
public string type { get; set; }
public List<dynamic> coordinates { get; set; }
}
public class Feature
{
public string type { get; set; }
public int id { get; set; }
public Properties2 properties { get; set; }
public Geometry geometry { get; set; }
}
public class Root
{
public string type { get; set; }
public string name { get; set; }
public Crs crs { get; set; }
public List<Feature> features { get; set; }
}
}
下面的示例 Json 文件。
{
"type": "FeatureCollection",
"name": "MYS_adm2",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "id": 0, "properties": { "ID_0": 136 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 102.911849975585938, 1.763612031936702 ], [ 102.911430358886832, 1.763888001442069 ] ] ] } },
{ "type": "Feature", "id": 1, "properties": { "ID_0": 136 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 103.556556701660156, 1.455448031425533 ], [ 103.555900573730582, 1.455950021743831 ] ] ] ] } },
【问题讨论】:
-
仅仅读取文本文件会消耗多少内存?也许不是将字符串加载到内存中,而是使用读取器对象?
-
你的意思是手动打开json文本文件?消耗了将近2GB。抱歉,您所说的使用阅读器对象是什么意思?介意分享一下吗?
-
打开文件进行读取,并将其传递给反序列化器而不是整个字符串,因此您可以尝试类似:
using (var reader = File.OpenText(@"path")) { Root root = (Root)new JsonSerializer().Deserialize(reader, typeof(Root)); }不幸的是,JsonConvert似乎没有静态反序列化方法接受阅读器,但改用 JsonSerializer 对象方法。 -
谢谢,我明白了。然而回到我的目的是动态读取 json 文件,所以这里不是使用
Root(实际上就像我说的那样工作),是否可以使用你建议的dynamic方法? -
using (var reader = File.OpenText(filePath)) { dynamic root = (dynamic)new JsonSerializer().Deserialize(new JsonTextReader(reader)); }也尝试过同样的异常。
标签: c# json geojson json-deserialization