使用CsvHelper解析CSV时单独提取id、其余字段转JSON为空如何解决
问题原因
你的代码有3个核心错误:
- 映射逻辑错误:你给
Json属性配置类型转换器时,CsvHelper默认会去CSV中查找名为Json的列,但你的CSV里不存在这个列,转换器根本拿不到输入值,自然返回空。 - 实体定义错误:你定义的
Json类只有GeoFeatures一个字符串属性,和CSV中除id外的其余字段(_npi_link_id/dtime/_dow等)完全不匹配,就算拿到值也无法正确序列化/反序列化。 - 逻辑理解错误:你需要的是把当前行除id外的所有列内容拼接为JSON,不是把某一个单元格的JSON字符串反序列化为对象,默认的列映射+类型转换器模式不适用这个场景。
正确实现方案
方案1:基于ClassMap的实现(推荐)
直接在映射规则里手动组装除id外的字段,不需要自定义类型转换器。
- 简化实体定义,不需要额外嵌套JSON类:
public class GeoFeatures { public string id { get; set; } // 存储其余字段序列化后的JSON字符串 public string ExtFieldsJson { get; set; } }
- 编写类映射规则,手动组装非id字段为JSON:
using CsvHelper.Configuration; using Newtonsoft.Json; public class FooMap : ClassMap<GeoFeatures> { public FooMap() { // 单独映射id字段 Map(m => m.id).Name("id"); // 手动处理剩余字段转JSON Map(m => m.ExtFieldsJson).Convert(row => { var extFields = new Dictionary<string, object>(); // 遍历所有表头,跳过id列 foreach (var header in row.Row.HeaderRecord) { if (header.Equals("id", StringComparison.OrdinalIgnoreCase)) continue; extFields[header] = row.Row.GetField(header); } // 序列化为JSON字符串返回 return JsonConvert.SerializeObject(extFields); }); } }
- 读取时注册映射即可:
var config = new CsvConfiguration(CultureInfo.InvariantCulture) { IgnoreBlankLines = true, HasHeaderRecord = true, HeaderValidated = null, MissingFieldFound = null, ShouldSkipRecord = record => string.IsNullOrEmpty(record.ToString()), }; using (var reader = new StreamReader(@"Z:\tmp\test3.csv")) using (var csv = new CsvReader(reader, config)) { // 注册自定义映射 csv.Context.RegisterClassMap<FooMap>(); var list = csv.GetRecords<GeoFeatures>().ToList(); // 测试输出 Console.WriteLine($"总记录数:{list.Count}"); Console.WriteLine($"第一条记录id:{list[0].id}"); Console.WriteLine($"第一条记录扩展字段JSON:{list[0].ExtFieldsJson}"); }
方案2:动态读取实现
如果不想写ClassMap,直接在循环读取时手动组装字段即可:
var config = new CsvConfiguration(CultureInfo.InvariantCulture) { IgnoreBlankLines = true, HasHeaderRecord = true, HeaderValidated = null, MissingFieldFound = null, ShouldSkipRecord = record => string.IsNullOrEmpty(record.ToString()), }; using (var reader = new StreamReader(@"Z:\tmp\test3.csv")) using (var csv = new CsvReader(reader, config)) { csv.Read(); csv.ReadHeader(); var headers = csv.HeaderRecord; var result = new List<GeoFeatures>(); while (csv.Read()) { var item = new GeoFeatures { id = csv.GetField<string>("id") }; var extFields = new Dictionary<string, object>(); foreach (var header in headers) { if (header == "id") continue; extFields[header] = csv.GetField(header); } item.ExtFieldsJson = JsonConvert.SerializeObject(extFields); result.Add(item); } }
运行后得到的ExtFieldsJson就是除id外所有字段的JSON结构,示例输出:
{"_npi_link_id":"3372355","dtime":"1","_dow":"2","congestion_cost":"0","vkt":"2.08","_delay_time":"0","vol":"11","_type":"Council Arterial","anes":"3","length":"189","eed_lim":"50","v_speed":"45.44"}
内容的提问来源于stack exchange,提问作者Samra
相关产品推荐
相关产品推荐

