用C#parsingC#中的CSV文件

有没有一个默认的/官方/推荐的方式来parsingC#中的CSV文件? 我不想推出我自己的parsing器。

另外,我也看到有人使用ODBC / OLE DB通过Text驱动来读取CSV文件,很多人因为“缺点”而不喜欢这个。 这些缺点是什么?

理想情况下,我正在寻找一种方法,我可以通过列名读取CSV,使用第一个logging作为标题/字段名称。 一些给出的答案是正确的,但基本反序列化文件到类。

让图书馆为您处理所有的细节问题! 🙂

检查FileHelpers和保持干爽 – 不要重复自己 – 没有必要重新发明轮子gazillionth时间….

你基本上只需要通过一个公共类(像默认值,NULL值replace等精心devise的属性)来定义数据的形状 – CSV中各行的字段,点在一个文件中的FileHelpers引擎,以及宾果 – 你从这个文件中取回所有的条目。 一个简单的操作 – 伟大的performance!

CSVparsing器现在是.NET Framework的一部分。

添加对Microsoft.VisualBasic.dll的引用(在C#中正常工作,不介意名称)

using (TextFieldParser parser = new TextFieldParser(@"c:\temp\test.csv")) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); while (!parser.EndOfData) { //Process row string[] fields = parser.ReadFields(); foreach (string field in fields) { //TODO: Process field } } } 

文档在这里 – TextFieldParser类

CsvHelper会将CSV文件读取到自定义对象中。

 var csv = new CsvReader( File.OpenText( "file.csv" ) ); var myCustomObjects = csv.GetRecords<MyCustomObject>(); 

有时你不拥有你想要读取的对象。 在这种情况下,你可以使用stream畅的映射,因为你不能在类上放置属性。

 public sealed class MyCustomObjectMap : CsvClassMap<MyCustomObject> { public MyCustomObjectMap() { Map( m => m.Property1 ).Name( "Column Name" ); Map( m => m.Property2 ).Index( 4 ); Map( m => m.Property3 ).Ignore(); Map( m => m.Property4 ).TypeConverter<MySpecialTypeConverter>(); } } 

在商业应用程序中,我使用codeproject.com, CSVReader上的开源项目。

运行良好,性能良好。 在我提供的链接上有一些基准。

一个简单的例子,从项目页面复制:

 using (CsvReader csv = new CsvReader(new StreamReader("data.csv"), true)) { int fieldCount = csv.FieldCount; string[] headers = csv.GetFieldHeaders(); while (csv.ReadNextRecord()) { for (int i = 0; i < fieldCount; i++) Console.Write(string.Format("{0} = {1};", headers[i], csv[i])); Console.WriteLine(); } } 

正如你所看到的,这很容易处理。

我知道它有点晚了,但只是find了一个库Microsoft.VisualBasic.FileIO它有TextFieldParser类来处理CSV文件。

如果你只需要阅读CSV文件,那么我推荐这个库: 一个快速的CSV阅读器
如果您还需要生成csv文件,然后使用这一个: FileHelpers

他们都是免费的,开源的。

这里是我经常使用的助手类,以防有人回到这个线程(我想分享它)。

我使用这个简单的将它移植到可以使用的项目中:

 public class CSVHelper : List<string[]> { protected string csv = string.Empty; protected string separator = ","; public CSVHelper(string csv, string separator = "\",\"") { this.csv = csv; this.separator = separator; foreach (string line in Regex.Split(csv, System.Environment.NewLine).ToList().Where(s => !string.IsNullOrEmpty(s))) { string[] values = Regex.Split(line, separator); for (int i = 0; i < values.Length; i++) { //Trim values values[i] = values[i].Trim('\"'); } this.Add(values); } } } 

并使用它:

 public List<Person> GetPeople(string csvContent) { List<Person> people = new List<Person>(); CSVHelper csv = new CSVHelper(csvContent); foreach(string[] line in csv) { Person person = new Person(); person.Name = line[0]; person.TelephoneNo = line[1]; people.Add(person); } return people; } 

[更新的csv帮手:修正了最后一个换行符创build一个新行的错误]

我已经写了.NET的TinyCsvParser ,它是最快的.NETparsing器之一,可以高度configuration来parsing几乎所有的CSV格式。

它在MIT许可下发布:

你可以使用NuGet来安装它。 在程序包pipe理器控制台中运行以下命令。

 PM> Install-Package TinyCsvParser 

用法

想象一下,我们有CSV文件persons.csv中的人名单,其名字,姓氏和出生date。

 FirstName;LastName;BirthDate Philipp;Wagner;1986/05/12 Max;Musterman;2014/01/02 

我们的系统中相应的域模型可能如下所示。

 private class Person { public string FirstName { get; set; } public string LastName { get; set; } public DateTime BirthDate { get; set; } } 

使用TinyCsvParser时,您必须定义CSV数据中的列与您的域模型中的属性之间的映射。

 private class CsvPersonMapping : CsvMapping<Person> { public CsvPersonMapping() : base() { MapProperty(0, x => x.FirstName); MapProperty(1, x => x.LastName); MapProperty(2, x => x.BirthDate); } } 

然后我们可以使用映射来parsingCsvParser的CSV数据。

 namespace TinyCsvParser.Test { [TestFixture] public class TinyCsvParserTest { [Test] public void TinyCsvTest() { CsvParserOptions csvParserOptions = new CsvParserOptions(true, new[] { ';' }); CsvPersonMapping csvMapper = new CsvPersonMapping(); CsvParser<Person> csvParser = new CsvParser<Person>(csvParserOptions, csvMapper); var result = csvParser .ReadFromFile(@"persons.csv", Encoding.ASCII) .ToList(); Assert.AreEqual(2, result.Count); Assert.IsTrue(result.All(x => x.IsValid)); Assert.AreEqual("Philipp", result[0].Result.FirstName); Assert.AreEqual("Wagner", result[0].Result.LastName); Assert.AreEqual(1986, result[0].Result.BirthDate.Year); Assert.AreEqual(5, result[0].Result.BirthDate.Month); Assert.AreEqual(12, result[0].Result.BirthDate.Day); Assert.AreEqual("Max", result[1].Result.FirstName); Assert.AreEqual("Mustermann", result[1].Result.LastName); Assert.AreEqual(2014, result[1].Result.BirthDate.Year); Assert.AreEqual(1, result[1].Result.BirthDate.Month); Assert.AreEqual(1, result[1].Result.BirthDate.Day); } } } 

用户指南

完整的用户指南可在以下url获得:

此解决scheme使用官方的Microsoft.VisualBasic程序集来parsingCSV。

优点:

  • 分隔符转义
  • 忽略标题
  • 修剪空间
  • 忽略评论

码:

  using Microsoft.VisualBasic.FileIO; public static List<List<string>> ParseCSV (string csv) { List<List<string>> result = new List<List<string>>(); // To use the TextFieldParser a reference to the Microsoft.VisualBasic assembly has to be added to the project. using (TextFieldParser parser = new TextFieldParser(new StringReader(csv))) { parser.CommentTokens = new string[] { "#" }; parser.SetDelimiters(new string[] { ";" }); parser.HasFieldsEnclosedInQuotes = true; // Skip over header line. //parser.ReadLine(); while (!parser.EndOfData) { var values = new List<string>(); var readFields = parser.ReadFields(); if (readFields != null) values.AddRange(readFields); result.Add(values); } } return result; } 

我正在寻找一个非常快速的解决scheme,不愿意添加额外的依赖关系。 由于我发现的不是我想做的最佳select,所以我写了自己的。 随意使用它。

更新代码在这里: https : //gist.github.com/mariodivece/9614872

没有官方的方式我知道,但你应该确实使用现有的库。 这里是我发现从CodeProject真正有用的一个:

http://www.codeproject.com/KB/database/CsvReader.aspx

基于如何正确使用C#split()函数分割CSV文件的不受限制的post? :

 string[] tokens = System.Text.RegularExpressions.Regex.Split(paramString, ","); 

注:这不会处理转义/嵌套逗号等,因此只适用于某些简单的CSV列表。

这是我的KISS实施…

 using System; using System.Collections.Generic; using System.Text; class CsvParser { public static List<string> Parse(string line) { const char escapeChar = '"'; const char splitChar = ','; bool inEscape = false; bool priorEscape = false; List<string> result = new List<string>(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < line.Length; i++) { char c = line[i]; switch (c) { case escapeChar: if (!inEscape) inEscape = true; else { if (!priorEscape) { if (i + 1 < line.Length && line[i + 1] == escapeChar) priorEscape = true; else inEscape = false; } else { sb.Append(c); priorEscape = false; } } break; case splitChar: if (inEscape) //if in escape sb.Append(c); else { result.Add(sb.ToString()); sb.Length = 0; } break; default: sb.Append(c); break; } } if (sb.Length > 0) result.Add(sb.ToString()); return result; } } 

前段时间我写了基于Microsoft.VisualBasic库的CSV读/写简单类。 使用这个简单的类,你将能够像使用2维数组一样使用CSV。 您可以通过以下链接find我的课程: https : //github.com/ukushu/DataExporter

用法的简单例子:

 Csv csv = new Csv("\t");//delimiter symbol csv.FileOpen("c:\\file1.csv"); var row1Cell6Value = csv.Rows[0][5]; csv.AddRow("asdf","asdffffff","5") csv.FileSave("c:\\file2.csv"); 

阅读标题只有你需要阅读csv.Rows[0]单元格:)

这段代码读取csv到DataTable:

 public static DataTable ReadCsv(string path) { DataTable result = new DataTable("SomeData"); using (TextFieldParser parser = new TextFieldParser(path)) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); bool isFirstRow = true; //IList<string> headers = new List<string>(); while (!parser.EndOfData) { string[] fields = parser.ReadFields(); if (isFirstRow) { foreach (string field in fields) { result.Columns.Add(new DataColumn(field, typeof(string))); } isFirstRow = false; } else { int i = 0; DataRow row = result.NewRow(); foreach (string field in fields) { row[i++] = field; } result.Rows.Add(row); } } } return result; } 

另一个列表, Cinchoo ETL – 一个用于读写多种文件格式(CSV,平面文件,Xml,JSON等)的开源库,

请在CodeProject上查看如何使用它的文章。