【问题标题】:C# Use CSV headers for assigning values to different variablesC# 使用 CSV 标头为不同的变量赋值
【发布时间】:2018-05-29 10:58:19
【问题描述】:

我正在读取一个 CSV 文件,并且基本上是在尝试使用标题来确定文件中值的序数位置,尽管最后一部分给我带来了一些麻烦。以下是我目前所拥有的:

private static IEnumerable<Cow> ReadCowStream(Stream source)
    {
        bool isHeader = true;
        var cows = new List<Cow>();

        using (var reader = new StreamReader(source))
        {
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                if (line != null)
                {
                    var values = line.Split(',');

                    if (isHeader && values.Contains("Weight") && values.Contains("Age"))
                    {
                        isHeader = false;
                    }
                    else
                    {
                        cows.Add(new Cow(
                            weight: values[0],
                            age: values[1]));
                    }
                }
            }
        }

        return animals;
    }

CSV 示例:

Weight,Age
300,10
319,11
100,1
370,9

在这种情况下,输出将是List&lt;Cow&gt;,其中第一个条目的值显然是“Weight”:“300”和“Age”:“10”,但是如果“Weight”和“Age”颠倒了怎么办?然后我会给错误的变量分配错误的值。

基本上,我想使用标题来确定是否将values[0] 放入weightage 等,因为我认为我不能保证在我正在阅读的CSV 中哪个排在第一位。

【问题讨论】:

  • 您可以只检查先出现的内容,即if(header[0] == 'Weight')[...] else [...],这是我想说的最简单的方法。
  • 考虑使用CsvHelper

标签: c# csv


【解决方案1】:

使用像CsvHelper 这样的库,可以根据标头名称而不是索引来提取值。

private static IEnumerable<Cow> ReadCowStream(Stream source) {
    var cows = new List<Cow>();
    using (var reader = new StreamReader(source)) {
        var csv = new CsvReader(reader);
        csv.Read();
        csv.ReadHeader();
        while (csv.Read()) {
            cows.Add(new Cow(weight: csv["Weight"], age: csv["Age"]));
        }
    }
    return cows;
}

所以现在读取的 CSV 中哪个标头首先出现并不重要。

该库允许进行强类型解析。

如果Cow 是使用默认构造函数定义的并且具有适当类型的属性

public class Cow {
    public int Age { get; set; }
    public int Weight { get; set; }
}

ReadCowStream 可以简化为

private static IEnumerable<Cow> ReadCowStream(Stream source) {
    using (var reader = new StreamReader(source)) {
        var csv = new CsvReader(reader);
        return csv.GetRecords<Cow>().ToList();
    }
}

CSV 阅读器将解析行、创建实例并通过将标题与属性名称匹配来分配值。

【讨论】:

  • 这是一个很酷很优雅的解决方案;我第一次使用 CsvHelper。
  • @Khaine775 添加了一些额外的细节。
【解决方案2】:

您可以存储标头索引,例如:

int weightIndex = Array.FindIndex(values, v => v == "Weight");
int ageIndex = Array.FindIndex(values, v => v == "Age");

然后按如下方式访问值:

cows.Add(new Cow(
    weight: values[weightIndex],
    age: values[ageIndex]));

【讨论】:

    【解决方案3】:

    使用Cinchoo ETL - 一个开源库,您只需几行代码即可轻松完成 csv 解析

    public class Cow
    {
        public int Age { get; set; }
        public int Weight { get; set; }
    }
    
    static void Main(string[] args)
    {
        string csv = @"Weight,Age
        300,10
        319,11
        100,1
        370,9";
    
        foreach (Cow rec in ChoCSVReader<Cow>.LoadText(csv).WithFirstLineHeader())
        {
            Console.WriteLine($"Age: {rec.Age}, Weight: {rec.Weight}");
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-08-31
      • 1970-01-01
      • 1970-01-01
      • 2013-02-25
      • 2012-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-23
      相关资源
      最近更新 更多