使用CsvHelper读取CSV时无法将科学计数法值转换为Int64

问题场景
现有CSV文件中Call_ID列的值以科学计数法格式存储(例如3.08E+12),需要将该列的长整型数值以Int64类型读取后存入列表,初始读取逻辑如下:
List<Model> result = null; using (StreamReader streamReader = new StreamReader(_excelFileConfiguration.Path + fileName)) { var csv = new CsvReader(streamReader, CultureInfo.InvariantCulture); csv.Context.RegisterClassMap<TestMap>(); result = csv.GetRecords<Model>().ToList(); }
初始定义的模型类与映射类如下:
public class Model { public int AccountId { get; set; } // 注意:原代码写的小写int64是C#语法错误,64位整型正确写法为long(对应System.Int64) public long CallId { get; set; } public DateTime Date { get; set; } } public sealed class TestMap : ClassMap<Model> { public TestMap() { Map(m => m.AccountId).Name("accountID"); Map(m => m.CallId).Name("Call_ID"); Map(m => m.Date).Name("Date"); } }
运行上述代码时抛出转换错误:The conversion cannot be performed. Text: '3.08E+12',默认转换器无法直接将科学计数法格式的字符串转为Int64类型。
解决方法
报错核心原因是CsvHelper内置的Int64类型转换器不支持直接解析科学计数法格式的数字字符串,通过自定义类型转换器即可解决,完整实现步骤如下:
- 编写自定义长整型转换器,兼容科学计数法格式解析
using CsvHelper; using CsvHelper.TypeConversion; using System.Globalization; public class ScientificNotationToLongConverter : DefaultTypeConverter { public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData) { if (string.IsNullOrWhiteSpace(text)) return 0L; // 优先解析科学计数法格式,转为double后再转long if (double.TryParse(text, NumberStyles.Float | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out double tempValue)) { return Convert.ToInt64(tempValue); } // 兼容普通整数字符串格式 return long.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out long longValue) ? longValue : base.ConvertFromString(text, row, memberMapData); } }
- 在类映射配置中,为
CallId字段绑定上述自定义转换器
public sealed class TestMap : ClassMap<Model> { public TestMap() { Map(m => m.AccountId).Name("accountID"); Map(m => m.CallId).Name("Call_ID").TypeConverter<ScientificNotationToLongConverter>(); Map(m => m.Date).Name("Date"); } }
如果不想单独定义转换器类,也可以直接在映射时写内联转换逻辑,效果完全一致:
public sealed class TestMap : ClassMap<Model> { public TestMap() { Map(m => m.AccountId).Name("accountID"); Map(m => m.CallId).Name("Call_ID").Convert(row => { var text = row.GetField("Call_ID"); if (double.TryParse(text, NumberStyles.Float | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out double temp)) { return Convert.ToInt64(temp); } return 0L; }); Map(m => m.Date).Name("Date"); } }
注意:如果
Call_ID的数值超过long类型最大值(9223372036854775807),需要改用ulong或者字符串类型存储,避免数值溢出。
内容的提问来源于stack exchange,提问作者nagaraj
相关产品推荐
相关产品推荐

