Разбор CSV, где заголовки содержат пробелы с CsvHelper
У меня есть файл CSV с заголовками полей, и некоторые из них содержат два или три слова, разделенные пробелами:
Вы можете видеть на рисунке выше заголовки полей, которые содержат пробелы:
"Время дня", "Имя процесса" и "Путь к изображению".
Когда я попытался прочитать CSV, позвонив reader.GetRecords<DataRecord>();
(где DataRecord
это класс, который я определил), я получаю ошибку:
Поля TimeOfDay не существуют в файле CSV."*
Это потому что мой DataRecord
класс не может содержать членов с пробелами.
Как я могу использовать CsvHelper для анализа файла CSV?
4 ответа
Основываясь на документации CsvHelper, мы можем достичь желаемых результатов несколькими способами.
1. Игнорировать пробелы в заголовках (которые, я считаю, должны легко решить вашу проблему)
В CsvHelper 3 или более поздней версии используйте PrepareHeaderForMatch
(задокументировано по адресу http://joshclose.github.io/CsvHelper/configuration) для удаления пробелов из заголовков:
csv.Configuration.PrepareHeaderForMatch =
header => Regex.Replace(header, @"\s", string.Empty)
В CsvHelper 2 установите IgnoreHeaderWhiteSpace
флаг, который говорит читателю игнорировать пробелы в заголовках при сопоставлении столбцов со свойствами по имени.
reader.Configuration.IgnoreHeaderWhiteSpace = true;
2. Читать вручную
Мы можем прочитать каждое поле вручную, например:
var reader = new CsvReader(sr);
do
{
reader.Read();
var record=new DataRecord();
record.TimeOfDay=reader.GetField<string>("Time of Day");
record.ProcessName=reader.GetField<string>("Process Name");
record.PID=reader.GetField<string>("PID");
record.Operation=reader.GetField<string>("Operation");
record.Path=reader.GetField<string>("Path");
record.Result=reader.GetField<string>("Result");
record.Detail=reader.GetField<string>("Detail");
record.ImagePath=reader.GetField<string>("Image Path");
} while (!reader.IsRecordEmpty());
3. Классовая картография:
Мы можем вручную отобразить между свойствами нашего класса и заголовками в файле CSV, используя name class mapping
как это:
public sealed class DataRecordMap:CsvClassMap<DataRecord>
{
public DataRecordMap()
{
Map( m => m.TimeOfDay).Name("Time Of Day");
Map( m => m.ProcessName).Name("Process Name");
Map( m => m.PID).Name("PID");
Map( m => m.Operation).Name("Operation");
Map( m => m.Path).Name("Path");
Map( m => m.Result).Name("Result");
Map( m => m.Detail).Name("Detail");
Map( m => m.ImagePath).Name("Image Path");
}
}
Тогда мы должны зарегистрировать это используя:
reader.Configuration.RegisterClassMap<DataRecordMap>();
Библиотека теперь поддерживает атрибуты. Вы хотели бы использовать атрибут имени.
public class DataRecord
{
[Name("Time of Day")]
public string TimeOfDay { get; set; }
[Name("Process Name")]
public string ProcessName { get; set; }
public string PID { get; set; }
public string Operation { get; set; }
public string Path { get; set; }
public string Result { get; set; }
public string Detail { get; set; }
[Name("Image Path")]
public string ImagePath { get; set; }
public static IEnumerable<DataRecord> ParseDataRecords(Stream file)
{
using (var sr = new StreamReader(file))
using (var csv = new CsvReader(sr))
{
foreach (var record in csv.GetRecords<DataRecord>())
{
yield return record;
}
}
}
}
После долгих попыток вот что сработало для меня. Я использую версию 3.
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
PrepareHeaderForMatch = args => args.Header.Replace(" ","")
};
using (var reader = new StreamReader("my_csv_file.csv"))
using (var csv = new CsvReader(reader, config))
Я считаю, что создаю конфигурацию (config), которая добавляет или изменяет InvariantCulture и использует функцию Replace в C # для удаления пробелов. Пока у меня работает.
Вы должны создать карту, http://joshclose.github.io/CsvHelper/mapping.