使用标头解析C#中的CSV文件

Dav*_*fer 248 c# csv io file-io header

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

此外,我已经看到人们使用ODBC/OLE DB通过Text驱动程序读取CSV的实例,很多人由于其"缺点"而不鼓励这种情况.这些缺点是什么?

Ideally, I'm looking for a way through which I can read the CSV by column name, using the first record as the header/field names. Some of the answers given are correct but work to basically deserialize the file into classes.

Ale*_*lex 335

CSV解析器现在是.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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

文档在这里 - TextFieldParser类

  • TextFieldParser实现了IDisposable,因此最好在using子句中使用它.否则回答很好. (6认同)
  • 在构造函数中,您可能希望使用与默认编码不同的编码,如下所示:new TextFieldParser("c:\ temp\test.csv",System.Text.Encoding.UTF8) (3认同)
  • 根据我的经验,TextFieldParser对大型(例如> 250Mb)文件的效果不佳.:( (2认同)
  • 请注意,如果 CSV 中的任何_field_包含空行,它们将被“TextFieldParser.ReadLine()”跳过。请参阅 [TextFieldParser 文档](https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser.readfields.aspx) (2认同)
  • 如何指定 csv 文件是否包含标题? (2认同)
  • 是否可以在.NET Core中获得此功能? (2认同)
  • 这个答案对初学者来说不是很有用,没有提到为了让此代码正常工作,您必须在文件开头添加“using Microsoft.VisualBasic.FileIO;”语句。 (2认同)
  • 请注意,如果您使用 `parser.SetDelimiters(",");`,则也不需要使用 `parser.TextFieldType = FieldType.Delimited;`。`SetDelimiters()` “将读取器的分隔符设置为指定值,**并将字段类型设置为 Delimited**。” (2认同)

Jos*_*ose 175

CsvHelper(我维护的库)会将CSV文件读入自定义对象.

var csv = new CsvReader( File.OpenText( "file.csv" ) );
var myCustomObjects = csv.GetRecords<MyCustomObject>();
Run Code Online (Sandbox Code Playgroud)

有时你不拥有你想要阅读的对象.在这种情况下,您可以使用流畅映射,因为您无法在类上放置属性.

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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我同意@ kubal5003.卖给我的是你把它作为NuGet包装出售.谢谢你,它很快,并且完成了我需要的所有csv阅读. (16认同)
  • 它太快了.在10秒内读取和反序列化130万条记录. (6认同)
  • CsvHelper 也不会将所有行加载到内存中。它加载一个小缓冲区并产生结果。您可能还想提及 SoftCircuits.CsvParser 由您维护。我相信这就是现在的政策。 (4认同)
  • 伟大的图书馆很容易实现.我只是建议Josh在这里更新他的答案,因为库已经改变了一点,因为这个答案已经编写了,你不能再实例化CsvHelper(它现在只是一个命名空间),但你必须使用CsvReader类. (2认同)
  • knocte,现在叫做 ClassMap。还有其他变化,比如在请求头记录之前必须进行读取(顺便说一下,它被设置为第一次调用 Read() 时读取的任何内容)。就像其他人之前提到的那样,它超快且易于使用。 (2认同)

mar*_*c_s 132

Let a library handle all the nitty-gritty details for you! :-)

Check out FileHelpers and stay DRY - Don't Repeat Yourself - no need to re-invent the wheel a gazillionth time....

您基本上只需要通过公共类(以及经过深思熟虑的属性,如默认值,NULL值的替换等等)来定义数据的形状 - CSV中各行中的字段(点) FileHelpers引擎在一个文件和宾果游戏 - 你从该文件中获取所有条目.一个简单的操作 - 性能卓越!

  • 截至2015年6月1日,我可以下载FileHelpers的唯一方法是在sourceforge.net上搜索它.这是使用的链接:http://sourceforge.net/projects/filehelpers/?source = directory (3认同)
  • @dotnetguy我们正在发布3.1(目前3.1-rc2)的方式.我们还重新设计了网站:www.filehelpers.net,您可以从那里下载最新版本 (2认同)
  • FileHelpers 无法正确处理 CSV 中的引号逗号,也无法实际映射字段标题,而是期望列的顺序与类型中声明的字段的顺序相同。就我个人而言,我不会使用它。 (2认同)

ale*_*exn 31

在业务应用程序中,我使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,它非常容易使用.


use*_*926 19

我知道它有点晚了,但刚刚发现了一个Microsoft.VisualBasic.FileIO具有TextFieldParser处理csv文件的类的库.


Gio*_*rgi 12

如果您只需要阅读csv文件,那么我推荐这个库:快速CSV阅读器
如果您还需要生成csv文件,请使用以下文件:FileHelpers

它们都是免费的和开源的.


Bas*_*e33 11

这是我经常使用的辅助类,以防任何人回到这个线程(我想分享它).

我使用它来简化将其移植到可以使用的项目中:

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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

并使用它像:

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;
}
Run Code Online (Sandbox Code Playgroud)

[更新了csv帮助程序:修复了最后一个新行字符创建新行的位置]

  • 如果任何csv条目包含逗号(,),则此代码将不起作用. (17认同)

Jon*_*ess 9

此解决方案使用官方Microsoft.VisualBasic程序集来解析CSV.

好处:

  • 分隔符逃逸
  • 忽略标题
  • 修剪空间
  • 忽略评论

码:

    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;
    }
Run Code Online (Sandbox Code Playgroud)


byt*_*ish 7

我编写了TinyCsvParser for .NET,它是最快的.NET解析器之一,可高度配置以解析几乎任何CSV格式.

它是在麻省理工学院许可下发布的:

您可以使用NuGet进行安装.在程序包管理器控制台中运行以下命令.

PM> Install-Package TinyCsvParser
Run Code Online (Sandbox Code Playgroud)

用法

想象一下,我们在CSV文件中列出了人员名单,persons.csv包括他们的名字,姓氏和生日.

FirstName;LastName;BirthDate
Philipp;Wagner;1986/05/12
Max;Musterman;2014/01/02
Run Code Online (Sandbox Code Playgroud)

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

private class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用映射来解析CSV数据CsvParser.

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用户指南

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


The*_*awk 6

这是一个简短的解决方案。

                using (TextFieldParser parser = new TextFieldParser(outputLocation))
                 {
                        parser.TextFieldType = FieldType.Delimited;
                        parser.SetDelimiters(",");
                        string[] headers = parser.ReadLine().Split(',');
                        foreach (string header in headers)
                        {
                            dataTable.Columns.Add(header);
                        }
                        while (!parser.EndOfData)
                        {
                            string[] fields = parser.ReadFields();
                            dataTable.Rows.Add(fields);
                        }
                    }
Run Code Online (Sandbox Code Playgroud)