获取CSV文件的特定单元格值

时间:2017-11-20 01:50:43

标签: c# csv filehelpers

我有一个示例csv文件,如下所示:

Index,Name,Age,Occupation
1,John,23,Driver
2,Jack,28,Painter
3,Alice,26,Accountant
4,Don,19,Student

而且,这是我的csv文件的类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FileHelpers;

namespace FileHelpersTester
{
    [DelimitedRecord(",")]
    [IgnoreFirst(1)]
    public class SpecDataOrder
    {
        public String Index;

        public String Name;

        public String Age;

        public String Occupation;
    }
}

我的主要方法如下:

namespace FileHelpersTester
{
    public class Program
    {
        static void Main(string[] args)
        {
            String specDataPath = @"C:\sample c# programs\FileHelpersTester\FileHelpersTester\bin\Debug\Sample.csv";
            String tester = GetValue(specDataPath, "2", SpecDataOrder.Name); //I expect the value of tester = "Jack"

        }

        public T GetValue<T>(String csvFilePath, String row, SpecDataOrder col)
        {
            var engine = new FileHelperEngine<SpecDataOrder>();
            var records = engine.ReadFile(csvFilePath);
            var dict = new Dictionary<String, SpecDataOrder>();

            foreach (var record in records)
            {
                dict[record.Index] = record;
            }
            return (T)Convert.ChangeType(dict[row].Index, typeof(T));
        }
    }    
}

我不确定我哪里出错了。这只是我在编写一个处理csv格式的大量数据的更复杂代码之前编写的测试程序。任何帮助都非常感谢。

2 个答案:

答案 0 :(得分:0)

此代码存在许多问题。

  1. 您正在尝试将字符串作为SpecDataOrder返回,该字符串永远无法正常工作
  2. 您正在尝试将对象的成员作为名称传递,但它实际上传递了值,因此需要对象的实例
  3. 您假设索引字段始终为“索引”,但在通用函数
  4. 中执行此操作
  5. 您正在创建所有记录的字典集合,只要您找到正确的索引就可以返回,因为您只想返回列
  6. 您正尝试从静态方法调用实例方法
  7. 要解决这四个问题,请尝试使用以下代码:

        static void Main(string[] args)
        {
            String specDataPath = @"C:\sample c# programs\FileHelpersTester\FileHelpersTester\bin\Debug\Sample.csv";
            String tester = GetValue<SpecDataOrder>(specDataPath, "2", nameof(SpecDataOrder.Index), nameof(SpecDataOrder.Name)) as string; //I expect the value of tester = "Jack"
    
        }
    
        public static object GetValue<T>(String csvFilePath, object rowIndex, String indexName, String fieldName)
        {
            var engine = new FileHelperEngine(typeof(T));
            var records = engine.ReadFile(csvFilePath);
    
            var memberIndex = new PropertyOrFieldInfo<T>(indexName);
            var memberField = new PropertyOrFieldInfo<T>(fieldName);
    
            foreach (T record in records)
            {
                var indexValue = memberIndex.GetValue(record);
                {
                    if (indexValue.Equals(rowIndex))
                    {
                        return memberField.GetValue(record);
                    }
                }
            }
            return null;
        }
    

    在Program.cs中拥有该代码后,您还需要添加以下类。请注意,此类使用反射来获取已传递的未知字段或属性详细信息,以便在有行时获取该字段/属性的值。反射确实会减慢您的代码速度,但有助于实现这种通用性。

    public class PropertyOrFieldInfo<T>
    {
        MemberInfo internalInfo;
        PropertyInfo internalProperty;
        FieldInfo internalField;
    
        public PropertyOrFieldInfo(string memberName)
        {
            internalProperty = typeof(T).GetProperty(memberName);
            if (internalProperty == null)
            {
                internalField = typeof(T).GetField(memberName);
                if (internalField == null)
                    throw new MissingMemberException(typeof(T).FullName, memberName);
            }
        }
    
        public object GetValue(T source)
        {
            if (internalProperty != null)
                return internalProperty.GetValue(source);
            else
                return internalField.GetValue(source);
        }
    }
    

    如果您正在计划更大规模的解决方案,请保留用于创建数据表的代码(但添加字典索引代码)并在两个不同的函数中返回单元格值。这样,您就不会为每个单元格查询重新创建表/字典。

    请注意,我没有在此处插入代码来检查空值等。您应该添加它以确保不调用null对象上的方法。

答案 1 :(得分:-1)

解决此问题的一种方法如下。但这会改变方法的签名有点得到价值。我不确定您是否可以在生产代码中更改它。

public static T GetValue<T>(String csvFilePath, int row, int col)
{
    string line = File.ReadLines(csvFilePath).Skip(row).Take(1).First();
    var x = line.Split(',');
    return (T)Convert.ChangeType(x[col-1], typeof(T));
}