使用C#读取CSV文件

ilk*_*kin 159 c# csv

我正在编写一个简单的导入应用程序,需要读取CSV文件,在a中显示结果DataGrid并在另一个网格中显示CSV文件的损坏行.例如,显示另一个网格中短于5个值的行.我试着这样做:

StreamReader sr = new StreamReader(FilePath);
importingData = new Account();
string line;
string[] row = new string [5];
while ((line = sr.ReadLine()) != null)
{
    row = line.Split(',');

    importingData.Add(new Transaction
    {
        Date = DateTime.Parse(row[0]),
        Reference = row[1],
        Description = row[2],
        Amount = decimal.Parse(row[3]),
        Category = (Category)Enum.Parse(typeof(Category), row[4])
    });
}
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,在阵列上操作非常困难.有没有更好的方法来分割价值观?

Dav*_*uda 346

不要重新发明轮子.利用.NET BCL中已有的功能.

  • 添加一个引用Microsoft.VisualBasic(是的,它说VisualBasic,但它也适用于C# - 请记住,最后它只是IL)
  • 使用Microsoft.VisualBasic.FileIO.TextFieldParser该类来解析CSV文件

以下是示例代码:

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

它在我的C#项目中对我很有用.

这里有一些更多的链接/信息:

  • 我真的希望有一种方法不使用VB库,但这完美无缺!谢谢! (17认同)
  • 另请查看:http://www.dotnetperls.com/textfieldparser.TextFieldParser的性能比String.Split和StreamReader差.但是,string.Split和TextFieldParser之间存在很大差异.TextFieldParser处理奇怪的情况,例如在列中使用逗号:您可以将列命名为"带引号的文本",以及逗号"`,您可以使用引号获取正确的值`文本",而不是错误地使用逗号`如果csv非常简单,那么你可能想要选择String.Split. (10认同)
  • +1很棒的答案,因为我发现很多人不知道这个类存在.未来观众需要注意的一件事是,如果你调用`parser.SetDelimiters(",");`,则设置`parser.TextFieldType = FieldType.Delimited;`,因为该方法为你设置`TextFieldType`属性. (9认同)
  • +1:我刚刚在53Mb文件上打破了lumenworks Fast CSV阅读器.看起来行缓存在43,000行之后失败并且对缓冲区进行了加扰.尝试了VB`TextFieldParser`它就可以了.谢谢 (5认同)
  • 请注意,您可能需要添加对Microsoft.VisualBasic的引用才能使用它.在Visual Studio中右键单击您的项目,然后选择"添加">"引用",并选中Microsoft.VisualBasic的复选框. (4认同)
  • 对于像我这样甚至不知道IL是什么的初学者,请查看http://www.codeproject.com/Articles/3778/Introduction-to-IL-Assembly-Language. (2认同)

adr*_*anm 36

我的经验是有许多不同的csv格式.特别是它们如何处理字段内的引号和分隔符的转义.

这些是我遇到的变种:

  • 报价被引用并加倍(excel)即15" - > field1,"15""",field3
  • 除非出于某些其他原因引用该字段,否则引号不会更改.即15" - > field1,15",fields3
  • 引号用\来转义.即15" - > field1,"15 \"",field3
  • 报价根本没有改变(这并不总是可以正确解析)
  • 引用分隔符(excel).即a,b - > field1,"a,b",field3
  • 分隔符用\来转义.即a,b - > field1,a \,b,field3

我已经尝试了许多现有的csv解析器,但没有一个可以处理我遇到的变种.从文档中找出解析器支持的转义变体也很困难.

在我的项目中,我现在使用VB TextFieldParser或自定义拆分器.

  • 主要问题是大多数实现不关心描述CSV格式的RFC 4180以及如何转义分隔符. (2认同)

kno*_*cte 22

我推荐Nuget的CsvHelper.

(添加对Microsoft.VisualBasic的引用感觉不对,它不仅难看,甚至可能不是跨平台的.)

  • 它与 C# 完全一样跨平台。 (4认同)
  • 错误,Linux中的Microsoft.VisualBasic.dll来自Mono源,它的实现与Microsoft的不同,并且有一些东西没有实现,例如:/sf/ask/465091581/微软-visualbasic-dll-for-mono-2-10 (4认同)
  • 是的,Microsoft.VisualBasic 命名空间在 .NET Core 2.1 上不可用 (2认同)

Man*_*ana 12

当您不想重新发明轮子时,有时使用库很酷,但在这种情况下,与使用库相比,可以用更少的代码行完成相同的工作并且更容易阅读.这是一种我觉得很容易使用的不同方法.

  1. 在这个例子中,我使用StreamReader来读取文件
  2. 正则表达式检测每行的分隔符.
  3. 用于从索引0到n收集列的数组

using (StreamReader reader = new StreamReader(fileName))
    {
        string line; 

        while ((line = reader.ReadLine()) != null)
        {
            //Define pattern
            Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");

            //Separating columns to array
            string[] X = CSVParser.Split(line);

            /* Do something with X */
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 当然,数据本身包含新行有问题吗? (4认同)
  • 当然,对于此类问题,基于字符的方法比正则表达式更自然。根据引号的存在,行为应该有所不同。 (2认同)

Kei*_*ows 6

CSV可以得到复杂的真正快.

使用强大且经过充分测试的东西:
FileHelpers: www.filehelpers.net

FileHelpers是一个免费且易于使用的.NET库,用于从文件,字符串或流中的固定长度或分隔记录中导入/导出数据.

  • 我认为FileHelper正试图一次性完成.解析文件是一个两步过程,您首先将行拆分为字段,然后将字段解析为数据.组合这些功能使得难以处理主 - 细节和线过滤等事情. (5认同)

Raj*_*ajN 6

此列表中的另一个,Cinchoo ETL - 一个用于读写 CSV 文件的开源库

对于下面的示例 CSV 文件

Id, Name
1, Tom
2, Mark
Run Code Online (Sandbox Code Playgroud)

您可以使用如下库快速加载它们

using (var reader = new ChoCSVReader("test.csv").WithFirstLineHeader())
{
   foreach (dynamic item in reader)
   {
      Console.WriteLine(item.Id);
      Console.WriteLine(item.Name);
   }
}
Run Code Online (Sandbox Code Playgroud)

如果您有与 CSV 文件匹配的 POCO 类

public class Employee
{
   public int Id { get; set; }
   public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用它来加载 CSV 文件,如下所示

using (var reader = new ChoCSVReader<Employee>("test.csv").WithFirstLineHeader())
{
   foreach (var item in reader)
   {
      Console.WriteLine(item.Id);
      Console.WriteLine(item.Name);
   }
}
Run Code Online (Sandbox Code Playgroud)

请查看CodeProject 中有关如何使用它的文章。

免责声明:我是这个库的作者