使用 CsvHelper 将 CSV 中的所有值读入列表

Posted

技术标签:

【中文标题】使用 CsvHelper 将 CSV 中的所有值读入列表【英文标题】:Read all values from CSV into a List using CsvHelper 【发布时间】:2015-10-23 04:10:32 【问题描述】:

所以我一直在阅读我不应该编写自己的 CSV 读取器/写入器,所以我一直在尝试使用通过 nuget 安装的 CsvHelper 库。 CSV 文件是灰度图像,行数为图像高度,列数为宽度。我想将值逐行读取到单个List<string>List<byte>

我目前的代码是:

using CsvHelper;

public static List<string> ReadInCSV(string absolutePath)

    IEnumerable<string> allValues;

    using (TextReader fileReader = File.OpenText(absolutePath))
    
        var csv = new CsvReader(fileReader);
        csv.Configuration.HasHeaderRecord = false;
        allValues = csv.GetRecords<string>
    

    return allValues.ToList<string>();

但是allValues.ToList&lt;string&gt;() 正在抛出:

CsvConfigurationException 未被用户代码处理

“CsvHelper.Configuration.CsvConfigurationException”类型的异常发生在 CsvHelper.dll 中,但未在用户代码中处理

附加信息:继承 IEnumerable 的类型不能自动映射。您是否不小心调用了作用于单个记录的 GetRecord 或 WriteRecord,而不是调用作用于记录列表的 GetRecords 或 WriteRecords?

GetRecords 可能期待我自己的自定义类,但我只是想要一些原始类型或字符串的值。另外,我怀疑整行都被转换为单个字符串,而不是每个值都是单独的字符串。

【问题讨论】:

你能给我们更多关于 CsvConfiguration 异常的信息吗?有消息吗? 像这样调用 .ToLIst() 几乎总是一个错误。尽可能长时间地使用 IEnumerable 以获得最佳性能。 显示您的 CSV 文件可能会有所帮助。无论如何,另一个选择是SoftCircuits.CsvParser。不确定它在这里是否有帮助,但我发现它的平均速度比 CsvHelper 快四倍。 【参考方案1】:

根据@Marc L 的帖子,您可以试试这个:

public static List<string> ReadInCSV(string absolutePath) 
    List<string> result = new List<string>();
    string value;
    using (TextReader fileReader = File.OpenText(absolutePath)) 
        var csv = new CsvReader(fileReader);
        csv.Configuration.HasHeaderRecord = false;
        while (csv.Read()) 
           for(int i=0; csv.TryGetField<string>(i, out value); i++) 
                result.Add(value);
            
        
    
    return result;

【讨论】:

这给出了我最初寻求的答案,所以我会接受这个作为答案,但我认为@MarcL。是正确的,因为 CsvHelper 似乎不是为我拥有的 CSV 文件设计的。 你知道你可以使用VB csv库来解析一个csv文件,对吧?您可以引用它并像使用 c# 库一样使用它。 var csv = new CsvReader(fileReader); 是否也应该在 using() 语句中,因为 CsvReader 是 IDisposable? (可能不是回答的时间)【参考方案2】:

如果你只需要数组中每一行的字符串值,你可以直接使用解析器。

var parser = new CsvParser( textReader );
while( true )

    string[] row = parser.Read();
    if( row == null )
    
        break;
    

http://joshclose.github.io/CsvHelper/#reading-parsing

更新

版本 3 支持读取和写入 IEnumerable 属性。

【讨论】:

只是好奇:这真的给了你任何你在File.ReadAllLines() 中没有得到的东西,证明添加另一个库依赖项的成本是合理的吗?另外,CsvParser 不是 IDisposable 吗? 它根据 RFC 4180 将行拆分为字段,有一些配置来处理非标准文件,然后像 Excel 一样回退到处理它。如果您的字段中有\n 怎么办? ReadAllLines() 会给你 2 行,而它只有 1 个 CSV 行。 我正在使用您创建的 csvhelper,我想将所有 csv 数据读入数据阅读器。是否有可能,因为我找不到任何说明如何在数据阅读器中转换数据的示例 什么是 textReader?【参考方案3】:

请试试这个。这对我有用。

TextReader reader = File.OpenText(filePath);
            CsvReader csvFile = new CsvReader(reader);
            csvFile.Configuration.HasHeaderRecord = true;
            csvFile.Read();
            var records = csvFile.GetRecords<Server>().ToList();

Server 是一个实体类。我就是这样创作的。

 public class Server
    
        private string details_Table0_ProductName;
        public string Details_Table0_ProductName
        
            get
            
                return details_Table0_ProductName;
            
            set
            
                this.details_Table0_ProductName = value;
            
        

        private string details_Table0_Version;
        public string Details_Table0_Version
        
            get
            
                return details_Table0_Version;
            
            set
            
                this.details_Table0_Version = value;
            
               
    

【讨论】:

【参考方案4】:

这里的重点是读取 CSV 的所有行并将其反序列化为对象集合。我不确定你为什么要将它作为字符串的集合来阅读。如前所述,在这种情况下,通用 ReadAll() 可能最适合您。当您将其用于此目的时,此库会大放异彩:

using System.Linq;

...
using (var reader = new StreamReader(path))
using (var csv = new CsvReader(reader))

    var yourList = csv.GetRecords<YourClass>().ToList();

如果您不使用ToList() - 它会一次返回一条记录(以获得更好的性能),请阅读https://joshclose.github.io/CsvHelper/examples/reading/enumerate-class-records

【讨论】:

【参考方案5】:

你很接近。并不是它试图将 row 转换为字符串。 CsvHelper 尝试使用标题行中给出的名称将行中的每个字段映射到您给它的类型的属性。此外,它不了解如何使用 IEnumerable 类型(string 实现)来执行此操作,因此它只会在自动映射到测试类型时抛出。


这对你正在做的事情来说很复杂。如果您的文件格式足够简单(您的文件格式似乎是众所周知的字段格式,既没有转义也没有引用分隔符),我认为您没有理由需要承担导入库的开销。您应该能够根据需要使用System.IO.File.ReadLines()String.Split() 枚举值。

//pseudo-code...you don't need CsvHelper for this
IEnumerable<string> GetFields(string filepath)

  foreach(string row in File.ReadLines(filepath))
  
    foreach(string field in row.Split(',')) yield return field;
  

【讨论】:

所以 CsvHelper 旨在处理具有特定列的 CSV 文件并将它们传递到包含这些列参数的自定义类?是否可以在我的情况下使用 CsvHelper,还是需要遍历每个字段? 老实说,我以前没有使用过它,但是阅读文档和您收到的错误意味着它不是为您的任务而构建的。您可能会扭曲它以获得您需要的东西,但我认为在这一点上,仅使用您可用的 CLR 工具会好得多。 我认为这不是正确的方法。 csv 文件可以包含带逗号的引用文本,并且不能以任何逗号分隔【参考方案6】:
static void WriteCsvFile(string filename, IEnumerable<Person> people)
    

        StreamWriter textWriter = File.CreateText(filename);

        var csvWriter = new CsvWriter(textWriter, System.Globalization.CultureInfo.CurrentCulture);

        csvWriter.WriteRecords(people);

        textWriter.Close();

    

【讨论】:

这不是“使用 CsvHelper 将所有值从 CSV 读取到列表中”的答案 - 此答案涉及写入文件。

以上是关于使用 CsvHelper 将 CSV 中的所有值读入列表的主要内容,如果未能解决你的问题,请参考以下文章

使用 CsvHelper 将 CSV 文件中的编号列映射到数组

将 CsvHelper 自定义转换器应用于一组类的所有字符串属性

使用 CsvHelper 将 csv 文件转换为 excel 时减少内存

如何使用 CSVHelper 更新现有 CSV 文件中特定列中的值?

使用 С# CSVHELPER 从 CSV 获取值时,代码重复

使用 CSVhelper 将单个列更新为先前编写的 CSV 文件。我有 Java 代码,但无法将其翻译成 C#