如何用C#将JSON转换为对象并读取大JSON文件?
嘿,我来帮你搞定这两个问题——先是你的JSON转C#对象失败的问题,再聊聊大文件读取的最佳实践~
一、修复C#类的映射问题
你当前的代码里手动用反射+JObject构造函数来取值,这不仅麻烦,还容易出错(比如你在Property类里错误地重复拿了type属性,而不是R_STATEFP和L_STATEFP)。其实Newtonsoft.Json(Json.NET)完全可以自动完成多层JSON到C#类的映射,根本不需要手动写这些构造函数。
重构后的C#类
直接用简洁的属性定义即可,Json.NET会自动匹配JSON字段名(注意大小写要对应,JSON里的字段名和类的属性名大小写一致就行):
using System.Collections.Generic; using Newtonsoft.Json; namespace MyApp { public class FeatureCollection { public string type { get; set; } public List<Feature> features { get; set; } } public class Feature { public string type { get; set; } public Property properties { get; set; } public Geometry geometry { get; set; } } public class Property { public string TYPE { get; set; } public string R_STATEFP { get; set; } public string L_STATEFP { get; set; } } public class Geometry { public string type { get; set; } public List<Coord> coordinates { get; set; } } public class Coord { // 用构造函数让Json.NET自动把[经度,纬度]数组转成Coord对象 [JsonConstructor] public Coord(double longitude, double latitude) { this.longitude = longitude; this.latitude = latitude; } public double longitude { get; set; } public double latitude { get; set; } } }
为什么原来的代码会失败?
你之前用i.GetType().GetProperty("type")是错误的思路:JObject是动态JSON对象,它的.GetType()返回的是.NET的JObject类型,这个类型的属性和JSON里的字段完全无关。正确的取值方式应该是i["type"].Value<string>(),但其实完全没必要这么做——Json.NET的自动映射已经帮你搞定了所有多层嵌套的匹配。
测试反序列化
现在你可以用一行代码完成反序列化(如果文件不算特别大的话):
var featureCollection = JsonConvert.DeserializeObject<FeatureCollection>(File.ReadAllText("your-file.json"));
二、大文件读取的最佳方式
如果你的JSON文件包含几百上千个Feature,甚至更大,直接用File.ReadAllText会把整个文件加载到内存,可能导致内存占用过高。最优方案是用JsonTextReader做流式处理,逐个读取Feature并处理,而不是一次性加载整个FeatureCollection。
流式读取示例代码
using System.IO; using Newtonsoft.Json; namespace MyApp { class Program { static void Main(string[] args) { var filePath = "your-large-file.json"; // 流式读取,逐个处理Feature using (var streamReader = new StreamReader(filePath)) using (var jsonReader = new JsonTextReader(streamReader)) { var serializer = new JsonSerializer(); // 定位到features数组的开始 while (jsonReader.Read()) { if (jsonReader.TokenType == JsonToken.StartArray && jsonReader.Path == "features") break; } // 逐个反序列化Feature while (jsonReader.Read()) { if (jsonReader.TokenType == JsonToken.EndArray) break; // 数组读完了,退出循环 if (jsonReader.TokenType == JsonToken.StartObject) { // 反序列化单个Feature var feature = serializer.Deserialize<Feature>(jsonReader); // 在这里处理每个Feature,比如存入数据库、打印信息等 Console.WriteLine($"读取到Feature:TYPE={feature.properties.TYPE}, 坐标数量={feature.geometry.coordinates.Count}"); } } } } } }
这种方式的优势是内存占用极低,因为每次只在内存中保留一个Feature对象,适合处理GB级别的大JSON文件。如果你的文件只是100+个Feature,其实直接反序列化整个FeatureCollection也没问题,但流式处理是更专业的大文件处理方案。
内容的提问来源于stack exchange,提问作者Amy

