c# - 如何将具有不同列标题的 .csv 文本文件中的数据导入内存
问题描述
我正在尝试一次从 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;
}
解决方案
正如人们的评论所说,我还建议使用现有的库。它们通常还支持您在代码中执行的到对象的数据映射和数据转换。所以,先试试一两个。
怎么样:
顺便说一句,就 Dictionary 中的项目顺序而言,您可以在此处阅读原因
出于枚举的目的,字典中的每个项目都被视为表示值及其键的 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;
}
}
推荐阅读
- python - Python:如何让一个while循环在另一个while语句中继续?
- java - DynamoDB 本地中的日期范围查询
- python - 导入 PyQt5 时如何修复“ModuleNotFound”错误?
- python - Selenium Webdriver 在尝试访问文本时返回 None
- reactjs - 如果我在 setState 方法中传递上一个状态值,为什么我的组件会再次呈现?
- javascript - 页面导航栏——不占空间
- c# - 异步/等待试图停止 Windows 服务
- python - 如果目录为空,则不创建新文件
- python - 如何将令牌传递给需要在 django rest 框架中进行身份验证的视图
- c# - 如何启用 json.net 的严格转换?