使用CsvHelper从单个csv文件读取多个类

问题描述:

最近我一直在使用Josh Close'CsvHelper来解析CSV文件,我非常喜欢流利的api用于类映射.

I've been using Josh Close' CsvHelper a bit recently to parse CSV files, I quite like the fluent api for class mapping.

我正在尝试映射包含多种记录类型的csv文件,文件结构为

I'm trying to map a csv file which contains multiple record types, the file structure is

C,Comment,Timestamp
I,Class1,Header1,Header2
D,Class1,Data1,Data2
D,Class1,Data1,Data2
...
I,Class2,Header1,Header2,Header3
D,Class2,Data1,Data2,Data3
D,Class2,Data1,Data2,Data3
...
C,Checksum

这是CsvHelper可以处理的吗?我已经编写了一个自定义解析器,该解析器基本上可以工作,但是它真正要做的就是为特定类过滤掉Header和Data字段-我真的很想能够做类似的事情

Is this something which can be handled by CsvHelper? I've writen a custom parser which basically works but all it really does is filter out the Header and Data fields for a specific class - I'd really like to be able to do something like

csv.Configuration.RegisterClassMap<Class1>();
csv.Configuration.RegisterClassMap<Class2>();

var data1 = csv.GetRecords<Class1>().ToList();             
var data2 = csv.GetRecords<Class2>().ToList();

一次读取文件?这可能还是我使用了错误的解析器?

And read the file in one pass? Is this possible or am I using the wrong parser?

问候戴夫

有一种方法可以做到;您只需要手动执行即可.

There is a way to do this; you just have to do it manually.

  1. 您手动逐行手动读取csv文件
  2. 检查第一列的鉴别符,以表明您需要映射到Class对象.
  3. 检查第二列以映射到该类.
  4. 将整个行映射到该给定的类.

  1. You manually read the csv file row by row
  2. Inspect the first column for the discriminator that will indicate that you need to map to a Class object.
  3. Inspect the second column for the class to map to.
  4. Map the entire row to that given class.

public static void ReadMultiClassCsv()
{
    var class1Data = new List<Class1>();
    var class2Data = new List<Class2>();

    using (StreamReader reader = File.OpenText(@"C:\filename.csv"))
    using (var csvReader = new CsvReader(reader))
    {
        //1.  You manually read the csv file row by row
        while (csvReader.Read())
        {
            var discriminator = csvReader.GetField<string>(0);

            //2.  Inspect the first column for the discriminator that will indicate that you need to map to a Class object.
            if (discriminator == "D")
            {
                var classType = csvReader.GetField<string>(1);

                //3.  Inspect the second column for the class to map to.
                switch (classType)
                {
                    //4.  Map the entire row to that given class.
                    case "Class1":
                        class1Data.Add(csvReader.GetRecord<Class1>());
                        break;
                    case "Class2":
                        class2Data.Add(csvReader.GetRecord<Class2>());
                        break;
                    default:
                        break;
                }
            }
        }
    }
}