如何将具有不同列标题的.csv文本文件中的数据导入内存

时间:2019-05-30 23:16:59

标签: c#

我正在尝试一次从CSV文件中读取一行数据。第一行,列标题,确定每一行中的数据类型。我已经知道所有数据都属于我的项目中有一个名为UserModel的类,但是我试图通过不将数据硬编码到UserModel字段来做到这一点。我能够阅读前两行,并正确创建用户模型的第一个实例。但是当我尝试阅读第三行时,事情就崩溃了。我正在使用词典,并且在阅读前几行时尝试使用创建的词典的实例。意思是使用Dictionary实例中的键顺序,只用下一组数据更新值,但是我无法弄清楚为什么该组数据不与正确的键对齐。

我在这里得到了一些很棒的代码并使用了它。 DictionaryToObject()方法就是其中之一。我认为我使用的循环超过了我的需要,并且不了解使用其他方式来访问某些数据结构,例如字符串数组,列表和字典。我是新手,可能在尝试获得所需结果时使用了错误的数据结构,甚至使用了一些不必要的代码。

public class MyData 
{
    BindingList<UserModel> users = new BindingList<UserModel>();
    UserModel currentUser = new UserModel();

    public BindingList<UserModel> GetUsers()
    {

        string[] lines = File.ReadAllLines("StandardDataSet.csv");
        // Add error handing to make sure all lines have four enteris 
        foreach (string line in lines.Skip(1))
        {
            //I am not sure how to handle the first line that is a header
            string [] values = line.Split(',').Select(x => x.Trim()).ToArray();
            currentUser.FirstName = values[0];
            currentUser.LastName = values[1];
            int.TryParse(values[2], out int age);
            currentUser.Age = age;
            bool.TryParse(values[3], out bool alive);
            currentUser.IsAlive = alive;
            users.Add(currentUser);
        }
        return users;
    }
private static T DictionaryToObject<T>(IDictionary<string, object> dict) where T : new()
    {
        T t = new T();
        PropertyInfo[] properties = t.GetType().GetProperties();

        foreach (PropertyInfo property in properties)
        {
            if (!dict.Any(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase)))
                continue;
            KeyValuePair<string, object> item = dict.First(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase));
            Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
            Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
            //if (item.Value is '0') Convert.ToBoolean(Convert.ToInt32(item.Value));
            object newA = Convert.ChangeType(item.Value, newT);
            t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
        }
        return t;
    }
public BindingList<UserModel> GetUsersAdvanced()
    {
        users = new BindingList<UserModel>();
        var dict= new Dictionary<string,object>();
        string[] lines = File.ReadAllLines("AdvancedDataSet.csv");
        var header = lines.First().Split(',');
        var data = lines.Skip(1).First().Split(',');


        for (int i = 0; i < header.Length; i++)
            {
                if (data[i] == "0" || data[i] == "1")
                    {
                        Boolean IsAlive = Extensions.ToBoolean(data[i]);
                        dict.Add(header[i], IsAlive);
                    }
                else
                //if (data[i]!= "0" || data[i]!="1")
                dict.Add(header[i], data[i]);
        }   
        currentUser = DictionaryToObject<UserModel>(dict);
        var dictCopy = new Dictionary<string, object>(dict);
        var dictConcurrent = new ConcurrentDictionary<string, object>(dict);

    foreach (var line in lines.Skip(1))
    {
    if (line != null)  data = line.Split(',');

                foreach (var key in dict.Keys)
                {
                int i = 0;
                if (data[i] == "0" || data[i] == "1")
                    {
                        Boolean IsAlive = Extensions.ToBoolean(data[i]);
                        dictCopy[key] = IsAlive;
                        i++;
                        continue;
                    }
                    else
                    dictCopy[key] = data[i];
                    i++;  
                 }
                 currentUser = DictionaryToObject<UserModel>(dictCopy);
                 users.Add(currentUser);
                 currentUser = new UserModel();

    }
 return users;
}

1 个答案:

答案 0 :(得分:0)

正如人们的评论所说,我还建议使用现有的库。它们通常还支持您在代码中执行的到对象的数据映射数据转换。因此,请先尝试一两个。

怎么样:

顺便说一下,按照字典中项目的顺序,您可以阅读原因here

  

出于枚举目的,字典中的每个项目都被视为代表值及其键的KeyValuePair结构。物品的退还顺序是不确定的。

那么,如何将列标题保留在列表中呢?这样,您可以保留订单。代码如下。

但是请仅将其作为订购商品的示例。再次,先尝试一些库,然后您将看到更酷的功能并获得更简洁的代码。

public BindingList<UserModel> GetUsersAdvanced()
{
    users = new BindingList<UserModel>();
    string[] lines = File.ReadAllLines("AdvancedDataSet.csv");
    var cols = lines.First().Split(',').ToList();

    // validate column name duplication here!

    foreach (var line in lines.Skip(1))
    {
        if (line != null)  data = line.Split(',');

        for (var i = 0; i < cols.Count(); i++)
        {
            var key = cols[i];
            var dict = new Dictionary<string, object>();

            if (data[i] == "0" || data[i] == "1")
            {
                Boolean IsAlive = Extensions.ToBoolean(data[i]);
                dict.Add(key, IsAlive);
            }
            else
                dict.Add(key, data[i]);

            var currentUser = DictionaryToObject<UserModel>(dict);
            users.Add(currentUser);
        }

        return users;
    }
}