本篇首先特別感謝今後啓程兄的《.NetCore外國一些高質量博客分享》, 發現不少國外的.NET Core技術博客資源, 我會不按期從中選擇一些有意思的文章翻譯總結一下。html
本篇博客來源於.NET Core Totorials的《CSV Parsing In .NET Core》。git
對於初級程序員來講, 使用string.Split(',')來解析CSV文件基本就是惟一可行的方法, 可是以後他們會發現除了使用逗號分隔值以外,CSV中還有其餘須要處理的東西,因此做者就介紹了CSV解析的一些痛點並推薦了2個比較好用CSV解析庫。程序員
這裏做者推薦了2個CSV解析庫,一個是CSVHelper, 一個是Tiny CSV Parser。github
爲了測試這些CSV解析庫,咱們首先建立一個.NET Core的控制檯程序app
而後咱們添加一個Automobile類,其代碼以下ide
public class Automobile { public string Make { get; set; } public string Model { get; set; } public AutomobileType Type { get; set; } public int Year { get; set; } public decimal Price { get; set; } public AutomobileComment Comment { get; set; } public override string ToString() { StringBuilder builder = new StringBuilder(); builder.AppendLine(); builder.AppendLine($"Make: {Make}"); builder.AppendLine($"Model: {Model}"); builder.AppendLine($"Type: {Type.ToString()}"); builder.AppendLine($"Year: {Year}"); builder.AppendLine($"Price: {Price}"); builder.AppendLine($"Comment: {Comment?.Comment}"); return builder.ToString(); } } public class AutomobileComment { public string Comment { get; set; } } public enum AutomobileType { None, Car, Truck, Motorbike }
最後咱們建立一個csv文件sample.txt做爲測試文件,咱們但願將當前csv文件中的數據,反序列化到一個Automobile
類的對象實例中。測試
其內容以下ui
Make,Model,Type,Year,Price,Comment "Toyota",Corolla,Car,1990,2000.99,"Comment with a, line break and "" quotes"
這個文件中第一行是一個表頭,第二行是一個數據行,數據行中包含了this
CSVHelper是一個CSV文件的讀寫庫。它支持讀寫自定義類對象。官網地址https://joshclose.github.io/CsvHelper/翻譯
咱們可使用Package Manager Console來安裝CSVHelper。
命令以下:
PM> Install-Package CsvHelper
使用CSVHelper解析CSV文件代碼很簡單, 還須要2步
CsvReader
類的對象實例讀取CSV文件GetRecords
方法來反序列化using (TextReader reader = new StreamReader("sample.txt")) { var csvReader = new CsvReader(reader); var records = csvReader.GetRecords<Automobile>(); foreach (var r in records) { Console.WriteLine(r.ToString()); } }
最終結果
從結果上看,上面提到的CSV解析痛點,CSVHelper都實現了,特別是針對Comment字段中的逗號、換行、雙引號,CSVHelper都處理的很成功。
下一個介紹的CSV解析器是Ting CSV Parser, 官網http://bytefish.github.io/TinyCsvParser/index.html, 它是使用配置的方式映射CSV字段, 使用方式上有點相似於AutoMapper
咱們可使用Package Manager Console來安裝Tiny CSV Parser。
命令以下:
PM> Install-Package TinyCsvParser
使用Tiny CSV Parser解析CSV文件,首先咱們須要建立一個映射類。映射類須要繼承自CsvMapping
映射類代碼
public class CsvAutomobileMapping : CsvMapping<Automobile> { public CsvAutomobileMapping() : base() { MapProperty(0, x => x.Make); MapProperty(1, x => x.Model); MapProperty(2, x => x.Type, new EnumConverter<AutomobileType>()); MapProperty(3, x => x.Year); MapProperty(4, x => x.Price); MapProperty(5, x => x.Comment, new AutomobileCommentTypeConverter()); } } public class AutomobileCommentTypeConverter : ITypeConverter<AutomobileComment> { public Type TargetType => typeof(AutomobileComment); public bool TryConvert(string value, out AutomobileComment result) { result = new AutomobileComment { Comment = value }; return true; } }
其中有幾個要點,
AutomobileCommentTypeConverter
。而後咱們修改Program.cs, 使用CsvParser
來解析sample.txt
CsvParserOptions csvParserOptions = new CsvParserOptions(true, ','); var csvParser = new CsvParser<Automobile>(csvParserOptions, new CsvAutomobileMapping()); var records = csvParser.ReadFromFile("sample.txt", Encoding.UTF8); foreach (var r in records) { if (r.IsValid) { Console.WriteLine(r.Result.ToString()); } }
最終結果
從結果上看,Tiny CSV Parser實現了大部分CSV解析的痛點,惟一不支持的是字符串換行,這一點須要注意。
文章的最後,做者使用Benchmark對CSVHelper和Tiny CSV Parser進行了效率比較。
測試代碼以下:
[MemoryDiagnoser] public class CsvBenchmarking { [Benchmark(Baseline =true)] public IEnumerable<Automobile> CSVHelper() { TextReader reader = new StreamReader("import.txt"); var csvReader = new CsvReader(reader); var records = csvReader.GetRecords<Automobile>(); return records.ToList(); } [Benchmark] public IEnumerable<Automobile> TinyCsvParser() { CsvParserOptions csvParserOptions = new CsvParserOptions(true, ','); var csvParser = new CsvParser<Automobile>(csvParserOptions, new CsvAutomobileMapping()); var records = csvParser.ReadFromFile("import.txt", Encoding.UTF8); return records.Select(x => x.Result).ToList(); } }
當測試100000行數據的時候
當測試1000000行數據的時候
從測試結果上看
Tiny Csv Parser的效率比CSVHelper高不少,內存佔用也少不少。