Escribir datos en un archivo CSV en C #

Estoy intentando escribir en un archivo csv fila por fila usando el lenguaje C #. Aquí está mi función

 string first = reader[0].ToString(); string second=image.ToString(); string csv = string.Format("{0},{1}\n", first, second); File.WriteAllText(filePath, csv); 

Toda la función se ejecuta dentro de un bucle, y cada fila debe escribirse en el archivo csv . En mi caso, la siguiente fila sobrescribe la fila existente y, al final, obtengo un solo registro en el archivo csv, que es el último. ¿Cómo puedo escribir todas las filas en el archivo csv ?

ACTUALIZAR

En mis días de ingenuidad, sugerí hacer esto manualmente (era una solución simple a una pregunta simple), sin embargo, debido a esto cada vez más popular, recomendaría usar la biblioteca CsvHelper que hace todos los controles de seguridad, etc.

CSV es mucho más complicado que lo que sugiere la pregunta / respuesta.

Respuesta original

Como ya tiene un bucle, considere hacerlo de esta manera:

 //before your loop var csv = new StringBuilder(); //in your loop var first = reader[0].ToString(); var second = image.ToString(); //Suggestion made by KyleMit var newLine = string.Format("{0},{1}", first, second); csv.AppendLine(newLine); //after your loop File.WriteAllText(filePath, csv.ToString()); 

O algo por el estilo Mi razonamiento es: no necesitarás escribir en el archivo para cada elemento, solo abrirás el flujo una vez y luego escribirás en él.

Puedes reemplazar

 File.WriteAllText(filePath, csv.ToString()); 

con

 File.AppendAllText(filePath, csv.ToString()); 

si desea mantener versiones anteriores de csv en el mismo archivo

C # 6

Si está usando c # 6.0 entonces puede hacer lo siguiente

 var newLine = $"{first},{second}" 

EDITAR

Aquí hay un enlace a una pregunta que explica qué hace Environment.NewLine

Recomiendo encarecidamente que tomes la ruta más tediosa. Especialmente si el tamaño de su archivo es grande.

 using(var w = new StreamWriter(path)) { for( /* your loop */) { var first = yourFnToGetFirst(); var second = yourFnToGetSecond(); var line = string.Format("{0},{1}", first, second); w.WriteLine(line); w.Flush(); } } 

File.AppendAllText() abre un nuevo archivo, escribe el contenido y luego cierra el archivo. Abrir archivos es una operación que requiere muchos recursos, que escribir datos en flujo abierto. Abrir \ el cierre de un archivo dentro de un bucle causará la caída del rendimiento.

El enfoque sugerido por Johan resuelve ese problema al almacenar todo el resultado en la memoria y luego escribirlo una vez. Sin embargo (en el caso de archivos grandes) el progtwig consumirá una gran cantidad de RAM e incluso se bloqueará con OutOfMemoryException

Otra ventaja de mi solución es que puede implementar la pausa \ reanudación guardando la posición actual en los datos de entrada.

upd. Colocado usando en el lugar correcto

Escribir archivos csv a mano puede ser difícil porque sus datos pueden contener comas y líneas nuevas. Le sugiero que use una biblioteca existente en su lugar.

Esta pregunta menciona algunas opciones.

¿Hay bibliotecas de lectores / escritores CSV en C #?

Utilizo una solución de dos análisis porque es muy fácil de mantener

 // Prepare the values var allLines = (from trade in proposedTrades select new object[] { trade.TradeType.ToString(), trade.AccountReference, trade.SecurityCodeType.ToString(), trade.SecurityCode, trade.ClientReference, trade.TradeCurrency, trade.AmountDenomination.ToString(), trade.Amount, trade.Units, trade.Percentage, trade.SettlementCurrency, trade.FOP, trade.ClientSettlementAccount, string.Format("\"{0}\"", trade.Notes), }).ToList(); // Build the file content var csv = new StringBuilder(); allLines.ForEach(line => { csv.AppendLine(string.Join(",", line)); }); File.WriteAllText(filePath, csv.ToString()); 

Simplemente use AppendAllText en su lugar:

 File.AppendAllText(filePath, csv); 

La única desventaja de AppendAllText es que generará un error cuando el archivo no exista, por lo que debe verificarse

Lo siento, momento rubio antes de leer la documentación . De todos modos, el método WriteAllText sobrescribe todo lo que se escribió previamente en el archivo, si el archivo existe.

Tenga en cuenta que su código actual no está utilizando nuevas líneas apropiadas, por ejemplo, en el Bloc de notas lo verá todo como una línea larga. Cambia el código a esto para tener nuevas líneas apropiadas:

 string csv = string.Format("{0},{1}{2}", first, image, Environment.NewLine); 

En lugar de llamar cada vez a AppendAllText() debería pensar en abrir el archivo una vez y luego escribir todo el contenido una vez:

 var file = @"C:\myOutput.csv"; using (var stream = File.CreateText(file)) { for (int i = 0; i < reader.Count(); i++) { string first = reader[i].ToString(); string second = image.ToString(); string csvRow = string.Format("{0},{1}", first, second); stream.WriteLine(csvRow); } } 
 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data; using System.Configuration; using System.Data.SqlClient; public partial class CS : System.Web.UI.Page { protected void ExportCSV(object sender, EventArgs e) { string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString; using (SqlConnection con = new SqlConnection(constr)) { using (SqlCommand cmd = new SqlCommand("SELECT * FROM Customers")) { using (SqlDataAdapter sda = new SqlDataAdapter()) { cmd.Connection = con; sda.SelectCommand = cmd; using (DataTable dt = new DataTable()) { sda.Fill(dt); //Build the CSV file data as a Comma separated string. string csv = string.Empty; foreach (DataColumn column in dt.Columns) { //Add the Header row for CSV file. csv += column.ColumnName + ','; } //Add new line. csv += "\r\n"; foreach (DataRow row in dt.Rows) { foreach (DataColumn column in dt.Columns) { //Add the Data rows. csv += row[column.ColumnName].ToString().Replace(",", ";") + ','; } //Add new line. csv += "\r\n"; } //Download the CSV file. Response.Clear(); Response.Buffer = true; Response.AddHeader("content-disposition", "attachment;filename=SqlExport.csv"); Response.Charset = ""; Response.ContentType = "application/text"; Response.Output.Write(csv); Response.Flush(); Response.End(); } } } } } } 

Manejo de Comas

Para manejar comas dentro de los valores cuando uso string.Format(...) , lo siguiente me ha funcionado:

 var newLine = string.Format("\"{0}\",\"{1}\",\"{2}\"", first, second, third ); csv.AppendLine(newLine); 

Entonces, para combinarlo con la respuesta de Johan, se vería así:

 //before your loop var csv = new StringBuilder(); //in your loop var first = reader[0].ToString(); var second = image.ToString(); //Suggestion made by KyleMit var newLine = string.Format("\"{0}\",\"{1}\"", first, second); csv.AppendLine(newLine); //after your loop File.WriteAllText(filePath, csv.ToString()); 

Devolución de archivo CSV

Si simplemente desea devolver el archivo en lugar de escribirlo en una ubicación, este es un ejemplo de cómo lo logré:

De un procedimiento almacenado

 public FileContentResults DownloadCSV() { // I have a stored procedure that queries the information I need SqlConnection thisConnection = new SqlConnection("Data Source=sv12sql;User ID=UI_Readonly;Password=SuperSecure;Initial Catalog=DB_Name;Integrated Security=false"); SqlCommand queryCommand = new SqlCommand("spc_GetInfoINeed", thisConnection); queryCommand.CommandType = CommandType.StoredProcedure; StringBuilder sbRtn = new StringBuilder(); // If you want headers for your file var header = string.Format("\"{0}\",\"{1}\",\"{2}\"", "Name", "Address", "Phone Number" ); sbRtn.AppendLine(header); // Open Database Connection thisConnection.Open(); using (SqlDataReader rdr = queryCommand.ExecuteReader()) { while (rdr.Read()) { // rdr["COLUMN NAME"].ToString(); var queryResults = string.Format("\"{0}\",\"{1}\",\"{2}\"", rdr["Name"].ToString(), rdr["Address"}.ToString(), rdr["Phone Number"].ToString() ); sbRtn.AppendLine(queryResults); } } thisConnection.Close(); return File(new System.Text.UTF8Encoding().GetBytes(sbRtn.ToString()), "text/csv", "FileName.csv"); } 

De una lista

 /* To help illustrate */ public static List list = new List(); /* To help illustrate */ public class Person { public string name; public string address; public string phoneNumber; } /* The important part */ public FileContentResults DownloadCSV() { StringBuilder sbRtn = new StringBuilder(); // If you want headers for your file var header = string.Format("\"{0}\",\"{1}\",\"{2}\"", "Name", "Address", "Phone Number" ); sbRtn.AppendLine(header); foreach (var item in list) { var listResults = string.Format("\"{0}\",\"{1}\",\"{2}\"", item.name, item.address, item.phoneNumber ); sbRtn.AppendLine(listResults); } } return File(new System.Text.UTF8Encoding().GetBytes(sbRtn.ToString()), "text/csv", "FileName.csv"); } 

Espero que esto sea útil.

En lugar de reinventar la rueda, se podría usar una biblioteca. CsvHelper es ideal para crear y leer archivos csv. Sus operaciones de lectura y escritura se basan en secuencias y, por lo tanto, también admiten operaciones con una gran cantidad de datos.


Puedes escribir tu csv de la siguiente manera.

 using(var textWriter = new StreamWriter(@"C:\mypath\myfile.csv")) { var writer = new CsvWriter(textWriter); writer.Configuration.Delimiter = ","; foreach (var item in list) { writer.WriteField( "a" ); writer.WriteField( 2 ); writer.WriteField( true ); writer.NextRecord(); } } 

Como la biblioteca está utilizando la reflexión, tomará cualquier tipo y lo analizará directamente.

 public class CsvRow { public string Column1 { get; set; } public bool Column2 { get; set; } public CsvRow(string column1, bool column2) { Column1 = column1; Column2 = column2; } } IEnumerable rows = new [] { new CsvRow("value1", true), new CsvRow("value2", false) }; using(var textWriter = new StreamWriter(@"C:\mypath\myfile.csv") { var writer = new CsvWriter(textWriter); writer.Configuration.Delimiter = ","; writer.WriteRecords(rows); } 

valor1, verdadero

value2, falso


Si desea leer más sobre las configuraciones y posibilidades de las bibliotecas, puede hacerlo aquí .

Es posible que solo deba agregar un avance de línea "\n\r" .

Aquí hay otra biblioteca de código abierto para crear archivos CSV fácilmente, Cinchoo ETL

 List objs = new List(); dynamic rec1 = new ExpandoObject(); rec1.Id = 10; rec1.Name = @"Mark"; rec1.JoinedDate = new DateTime(2001, 2, 2); rec1.IsActive = true; rec1.Salary = new ChoCurrency(100000); objs.Add(rec1); dynamic rec2 = new ExpandoObject(); rec2.Id = 200; rec2.Name = "Tom"; rec2.JoinedDate = new DateTime(1990, 10, 23); rec2.IsActive = false; rec2.Salary = new ChoCurrency(150000); objs.Add(rec2); using (var parser = new ChoCSVWriter("emp.csv").WithFirstLineHeader()) { parser.Write(objs); } 

Para obtener más información, lea el artículo de CodeProject sobre el uso.

Este es un tutorial simple sobre cómo crear archivos csv usando C # que podrá editar y ampliar para adaptarlo a sus necesidades.

Primero tendrá que crear una nueva aplicación de consola Visual Studio C #, hay pasos a seguir para hacer esto.

El código de ejemplo creará un archivo csv llamado MyTest.csv en la ubicación que especifique. El contenido del archivo debe tener 3 columnas nombradas con texto en las primeras 3 filas.

https://tidbytez.com/2018/02/06/how-to-create-a-csv-file-with-c/

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace CreateCsv { class Program { static void Main() { // Set the path and filename variable "path", filename being MyTest.csv in this example. // Change SomeGuy for your username. string path = @"C:\Users\SomeGuy\Desktop\MyTest.csv"; // Set the variable "delimiter" to ", ". string delimiter = ", "; // This text is added only once to the file. if (!File.Exists(path)) { // Create a file to write to. string createText = "Column 1 Name" + delimiter + "Column 2 Name" + delimiter + "Column 3 Name" + delimiter + Environment.NewLine; File.WriteAllText(path, createText); } // This text is always added, making the file longer over time // if it is not deleted. string appendText = "This is text for Column 1" + delimiter + "This is text for Column 2" + delimiter + "This is text for Column 3" + delimiter + Environment.NewLine; File.AppendAllText(path, appendText); // Open the file to read from. string readText = File.ReadAllText(path); Console.WriteLine(readText); } } } 

Una forma simple de deshacerse del problema de sobreescritura es usar File.AppendText para agregar una línea al final del archivo como

 void Main() { using (System.IO.StreamWriter sw = System.IO.File.AppendText("file.txt")) { string first = reader[0].ToString(); string second=image.ToString(); string csv = string.Format("{0},{1}\n", first, second); sw.WriteLine(csv); } }