在c#中是否有默认/官方/推荐的方法来解析CSV文件?我不想滚动自己的解析器。

另外,我也见过人们使用ODBC/OLE DB通过文本驱动程序读取CSV的实例,很多人因为它的“缺点”而不鼓励这样做。这些缺点是什么?

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


当前回答

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

我这样做是为了简单地将它移植到可以使用的项目中:

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 helper:修复了最后一个新行字符创建新行的错误]

其他回答

对于较小的CSV输入数据,LINQ是完全足够的。 以以下CSV文件内容为例:

schema_name、描述utype “IX_HE”、“高能量数据”,“x” “III_spectro”、“Spectrosopic数据”、“d” “VI_misc”、“杂”、“f” “vcds1”,“目录只在cd上提供”,“d” “J_other”,“其他期刊发表的文章”,“b”

当我们将整个内容读入一个名为data的字符串时,则

using System;
using System.IO;
using System.Linq;

var data = File.ReadAllText(Path2CSV);

// helper split characters
var newline = Environment.NewLine.ToCharArray();
var comma = ",".ToCharArray();
var quote = "\"".ToCharArray();

// split input string data to lines
var lines = data.Split(newline);

// first line is header, take the header fields
foreach (var col in lines.First().Split(comma)) {
    // do something with "col"
}

// we skip the first line, all the rest are real data lines/fields
foreach (var line in lines.Skip(1)) {
    // first we split the data line by comma character
    // next we remove double qoutes from each splitted element using Trim()
    // finally we make an array
    var fields = line.Split(comma)
        .Select(_ => { _ = _.Trim(quote); return _; })
        .ToArray();
    // do something with the "fields" array
}

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

我这样做是为了简单地将它移植到可以使用的项目中:

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 helper:修复了最后一个新行字符创建新行的错误]

让一个库为你处理所有的细节!: -)

检查FileHelpers和保持干燥-不重复自己-不需要重新发明轮子的亿万次....

基本上,您只需要定义数据的形状——CSV中各个行中的字段——通过一个公共类(以及诸如默认值、NULL值替换等经过精心考虑的属性),将FileHelpers引擎指向一个文件,然后就可以从该文件中获得所有条目。一个简单的操作-卓越的性能!

这个列表中的另一个,Cinchoo ETL -一个开源库,可以读写多种文件格式(CSV,平面文件,Xml, JSON等)

下面的示例显示了如何快速读取CSV文件(不需要POCO对象)

string csv = @"Id, Name
1, Carl
2, Tom
3, Mark";

using (var p = ChoCSVReader.LoadText(csv)
    .WithFirstLineHeader()
    )
{
    foreach (var rec in p)
    {
        Console.WriteLine($"Id: {rec.Id}");
        Console.WriteLine($"Name: {rec.Name}");
    }
}

下面的示例展示了如何使用POCO对象读取CSV文件

public partial class EmployeeRec
{
    public int Id { get; set; }
    public string Name { get; set; }
}

static void CSVTest()
{
    string csv = @"Id, Name
1, Carl
2, Tom
3, Mark";

    using (var p = ChoCSVReader<EmployeeRec>.LoadText(csv)
        .WithFirstLineHeader()
        )
    {
        foreach (var rec in p)
        {
            Console.WriteLine($"Id: {rec.Id}");
            Console.WriteLine($"Name: {rec.Name}");
        }
    }
}

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

CsvHelper(我维护的一个库)将把CSV文件读入自定义对象。

using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    var records = csv.GetRecords<Foo>();
}

有时候你并不拥有你想读的对象。在这种情况下,您可以使用流畅映射,因为您不能将属性放在类上。

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>();
    }
}