Как можно преобразовать файл csv в список объектов C#?
Есть файл со следующим содержимым (привел только самые первые две строки, там строк со значениями около 1500):
Id_1C;Id;Group_id;Producer;Partnumber;Prefix;Name;Addon;Selling;Status;Тип;механизма;Материал;корпуса;Циферблат;Цифры;Бой;Маятник;Ночной;режим;Ширина;Высота;Глубина
CB002590925;1706267;0;TFA;TFA;60.3062.51;Настеные;часы;60.3062;PICUS;(Зеленый;дятел),;розовое;золото;;0;0;*кварцевые;*алюминий;*золотистый;*отсутствуют;*нет;*да;*нет;
Как из этого можно преобразовать в объект C#? Ничего вменяемого не нашел, кроме как использовать Visual Basic, но мне бы очень не хотелось этим заниматься. Конечно, можно руками, но мне бы тоже не хотелось вручную парсить 20 свойств
Ответы (2 шт):
Сделал на скорую руку вот такой вот код (оставляет желать лучшего).
- Начал с атрибута которым нужно пометить свойство. В конструктор передается имя колонки в
*.csvфайле.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
sealed class CsvPropertyAttribute : Attribute
{
public CsvPropertyAttribute(string csvName)
{
CsvName = csvName;
}
public string CsvName { get; set; }
}
- Небольшой класс в котором сначала обрабатываются строки. Метод FormatFile возвращает элементы в виде
ColumnName - ValueN. В методе Parse преобразую это вIEnumerable<KeyValuePair<string, IList<string>>ну и преобразую с помощью цикла в нужные объекты
class CsvProvider
{
public static IEnumerable<T> Parse<T>(IList<string> lines, char separator)
where T : new()
{
var props = typeof(T).GetProperties().Where(
x => Attribute.IsDefined(x, typeof(CsvPropertyAttribute))).ToArray();
var propertyValuesPairs = FormatFile(lines, separator)
.GroupBy(x => x.Item1)
.Select(x => new KeyValuePair<string, IList<string>>(x.Key, x.Select(x => x.Item2).ToList()))
.ToList();
int count = propertyValuesPairs.First().Value.Count;
var items = propertyValuesPairs.Where(x => props.Select(x => x.Name).Contains(x.Key));
for (int i = 0; i < count; i++)
{
var obj = new T();
foreach (var item in items)
{
PropertyInfo property = props.FirstOrDefault(
x => x.GetCustomAttribute<CsvPropertyAttribute>().CsvName == item.Key);
if (property == null)
continue;
property.SetValue(obj, Convert.ChangeType(item.Value[i], property.PropertyType), null);
}
yield return obj;
}
}
private static IEnumerable<(string, string)> FormatFile(IList<string> lines, char separator)
{
var properties = lines[0].Split(separator).ToList();
properties.RemoveAll(x => string.IsNullOrEmpty(x));
lines.RemoveAt(0); //самая первая строка в файле csv (содержатся названия для колонок)
foreach (var item in lines)
{
var values = item.Split(separator).ToList();
for (int i = 0; i < properties.Count; i++)
{
yield return (properties[i], values[i]);
}
}
}
}
Только только решил подобную задачу. Задавался вопросом, что лучше использовать и нашел решение в виде CsvHelper
Можно сразу создать класс
public class Record
{
public int Id { get; set; }
public string Id_1C { get; set; }
public string Group_id { get; set; }
public string Producer{ get; set; }
public string Partnumber{ get; set; }
// и так далее
}
и сразу вот так
void Main()
{
using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
var records = csv.GetRecords<Record>();
}
}
Все
По мотивам документации
Для сопоставления имен колонок в файле и полем в классе есть возможность использовать Mapping Properties