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

Read all values from CSV into a List using CsvHelper

所以我一直在读到我不应该编写自己的 CSV reader/writer,所以我一直在尝试使用通过 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<string>() 正在抛出一个:

用户代码未处理 CsvConfigurationException

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

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

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

你很接近。这并不是说它试图将 转换为字符串。 CsvHelper 尝试使用 header 行中给定的名称将行中的每个字段映射到您为其指定的类型的属性。此外,它不明白如何使用 IEnumerable 类型(string 实现)来执行此操作,因此它只是在 auto-mapping 达到测试类型的那个点时抛出。


对于您正在做的事情来说,这太复杂了。如果您的文件格式足够简单,您的文件格式似乎是——众所周知的字段格式,既没有转义分隔符也没有引号分隔符——我认为您没有理由需要承担导入库的开销。您应该能够根据需要使用 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;
  }
}

根据@Marc L 的 post 你可以试试这个:

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

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

var parser = new CsvParser( textReader );
while( true )
{
    string[] row = parser.Read();
    if( row == null )
    {
        break;
    }
}

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

更新

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

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

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

服务器是一个实体class。我就是这样创建的。

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

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

using System.Linq;

...
using (var reader = new StreamReader(path))
using (var csv = new CsvReader(reader))
{
    var yourList = csv.GetRecords<YourClass>().ToList();
}

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

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

    }