Escribir un encabezado utilizando CsvHelper? DO#

Estoy usando CsvHelper. Para escribir en un archivo .csv , necesito un encabezado basado en una clase.

Escribo el encabezado manualmente y funciona, pero debo hacerlo automáticamente cuando se lee.

Toda la documentación que puedo encontrar dice usar esta expresión, writer.WriteHeader(); pero eso no está funcionando porque necesita más trabajo.

Aquí está la clase en la que el encabezado debe basarse:

 public class CSVDataFormat { public string FirstName { get; set; } public string LastName { get; set; } public float Wage { get; set; } } 

Aquí está el código para la lectura y escritura:

 private void ReadCSV(string ogCsvFile) { using (var streamReaederfileDir = new StreamReader(@ogCsvFile)) { using (var streamWriterFileDir = new StreamWriter(Path.Combine(Path.GetDirectoryName(ogCsvFile), "New" + Path.GetFileName(ogCsvFile)))) { var reader = new CsvReader(streamReaederfileDir); var writer = new CsvWriter(streamWriterFileDir); writer.WriteHeader(); IEnumerable records = reader.GetRecords().ToList(); foreach (CSVDataFormat record in records) { record.Wage = record.Wage + (record.Wage / 10); writer.WriteField(record.FirstName); writer.WriteField(record.LastName); writer.WriteField(record.Wage); writer.NextRecord(); } } } } 

Actualizar

Este es el error que recibo cuando ejecuto mi código:

Se produjo una excepción no controlada de tipo ‘CsvHelper.CsvMissingFieldException’ en CsvHelper.dll

Información adicional: los campos ‘Nombre’ no existen en el archivo CSV.

Puede estar confundido cómo funciona CSVHelper. Este código maneja el aspecto de escritura de su ciclo de lectura y escritura:

 List empList = new List(); empList.Add(new Employee { FirstName = "Ziggy", LastName = "Walters", Wage = 132.50F }); empList.Add(new Employee { FirstName = "Zoey", LastName = "Strand", Wage = 76.50F }); using (StreamWriter sw = new StreamWriter(@"C:\Temp\emp.csv")) using (CsvWriter cw = new CsvWriter(sw)) { cw.WriteHeader(); foreach (Employee emp in empList) { emp.Wage *= 1.1F; cw.WriteRecord(emp); } } 
  • CSVWriter implementa IDisposable , así que lo puse en un bloque de uso también.
  • El ajuste salarial es ligeramente racionalizado.

Resultado:

Nombre, Apellido, Salario
Ziggy, Walters, 145.75
Zoey, Strand, 84.15

El encabezado de escritura solo escribe la primera línea: los nombres de las columnas / elementos. Observe que los salarios enumerados son diferentes de los que usé para crear cada uno.

Por lo que está haciendo, leería un objeto escrito en lugar de iterar la lista de empList . Para el error listado en la edición, eso significa que no pudo encontrar una columna con ese nombre en el archivo de entrada (probablemente porque no usó la sobrecarga de Tipos). Los nombres de las propiedades de la clase deben coincidir exactamente con los nombres de las columnas (es posible que también desee configurar CSVHelper).


El bucle completo de entrada y salida es solo un poco más complejo:

 using (StreamReader sr = new StreamReader(@"C:\Temp\empIN.csv")) using (StreamWriter sw = new StreamWriter(@"C:\Temp\empOUT.csv")) using (CsvWriter cw = new CsvWriter(sw)) using (CsvReader cr = new CsvReader(sr)) { cw.WriteHeader(); var records = cr.GetRecords(); foreach (Employee emp in records) { emp.Wage *= 1.1F; cw.WriteRecord(emp); } } 

Resultados utilizando la salida del primer bucle como entrada:

Nombre, Apellido, Salario
Ziggy, Walters, 160.325
Zoey, Strand, 92.565


Si no hay un registro de encabezado en el CSV entrante, no sabrá cómo asignar datos a la clase. Necesitas agregar un mapa:

 public class EmployeeMap : CsvHelper.Configuration.CsvClassMap { public EmployeeMap() { Map(m => m.FirstName).Index(0); Map(m => m.LastName).Index(1); Map(m => m.Wage).Index(2); } } 

El mío está nested dentro de la clase Employee . Entonces dale a CSVHelper ese mapa:

 ... before your try to read from the incoming CSV: cr.Configuration.RegisterClassMap(); cw.WriteHeader(); ... 

Ahora sabe cómo asignar columnas csv a las propiedades en su clase.

Creo que esta excepción es del CsvReader y no del CsvWriter. CsvConfiguration predeterminado espera un encabezado y utiliza AutoMap para generar un mapeo PropertyName_to_Index.

De la documentación puede que necesite definir un mapa, ver mapeo