Gravar os dados no ficheiro CSV em C#

estou a tentar escrever numa file row por linha usando a linguagem C#. Aqui está a minha função

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

Toda a função corre dentro de um laço, e cada linha deve ser escrita no ficheiro csv. No meu caso a próxima linha sobrepõe a linha existente e no final estou recebendo apenas um único registro no arquivo csv que é o último. Como posso escrever todas as linhas no ficheiro csv.

 125
Author: Ben, 2013-09-12

14 answers

Actualizar

[[6]] de volta aos meus dias de ingenuidade, eu sugeri fazer isso manualmente( era uma solução simples para uma pergunta simples), no entanto, devido a isso se tornando cada vez mais popular, eu recomendaria usar a biblioteca CsvHelper que faz todas as verificações de segurança, etc. A CSV é muito mais complicada do que o que a pergunta/resposta sugere.

Resposta Original

Como já tens um loop, considera fazê-lo assim:

//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());

Ou algo para este efeito. Meu raciocínio é: você não será necessário escrever para o arquivo para cada item, você só vai abrir o fluxo uma vez e, em seguida, escrever para ele.

Podes substituir

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

Com

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

Se quiser manter as versões anteriores do csv no mesmo ficheiro

C# 6

Se estiver a utilizar c# 6, 0 então pode fazer o seguinte

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

Editar

Aqui está um linkpara uma pergunta que explica o que Environment.NewLine

 207
Author: Johan, 2018-01-17 13:34:10
Recomendo-lhe que siga o caminho mais aborrecido. Especialmente se o seu tamanho de arquivo é 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 um novo ficheiro, escreve o conteúdo e, em seguida, fecha o ficheiro. Abrir arquivos é uma operação muito pesada de recursos, do que escrever dados em fluxo aberto. Abrir\fechar um ficheiro dentro de um loop fará com que o desempenho caia.

A abordagem sugerida por Johan resolve esse problema armazenando toda a saída na memória e depois escrevendo-a uma vez. No entanto (em caso de grandes Ficheiros) o seu programa irá consumir uma grande quantidade de RAM e até estoirar com OutOfMemoryException

Outra vantagem da minha solução é que você pode implementar a pausa\retomando gravando a posição actual nos dados de entrada.

Upd. Colocado no local certo

 66
Author: Pavel Murygin, 2014-10-12 22:47:21

Escrever ficheiros csv à mão pode ser difícil porque os seus dados podem conter vírgulas e linhas novas. Sugiro que use uma biblioteca existente.

Esta pergunta menciona algumas opções.

Há alguma biblioteca de leitores/escritores CSV em C#?

 23
Author: Jeppe Andreasen, 2017-05-23 10:31:15

Uso uma solução de duas partes porque é muito fácil de manter

// 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());
 14
Author: user3495843, 2014-04-03 23:11:15

Em vez disso, basta usar o texto do apêndice:

File.AppendAllText(filePath, csv);

a única desvantagem do texto do apêndice é que ele irá lançar o erro quando o ficheiro não existe, por isso isto deve ser assinalado

Desculpa, momento loiro antes de ler a documentação . De qualquer forma, o método WriteAllText sobrepõe tudo o que foi escrito anteriormente no arquivo, se o arquivo existir.

Note que o seu código actual não está a usar novas linhas adequadas, por exemplo no bloco de notas, verá tudo como uma longa fila. Mude o código para isto para ter novas linhas adequadas:

string csv = string.Format("{0},{1}{2}", first, image, Environment.NewLine);
 9
Author: Shadow Wizard, 2013-09-12 06:49:22

Em vez de ligar sempre AppendAllText() devias pensar em abrir o ficheiro Uma vez e depois escrever todo o conteúdo uma 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);
    }
}
 6
Author: Oliver, 2017-11-06 10:21:17
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();
                    }
                }
            }
        }
    }
}
 5
Author: Alejandro Haro, 2016-03-26 04:45:50
Em vez de reinventar a roda, poderia usar-se uma biblioteca. {[2] } é óptimo para criar e ler ficheiros csv. As operações de leitura e escrita são baseadas em stream e, portanto, também suportam operações com uma grande quantidade de dados.
Podes escrever o teu csv como se segue.
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 a biblioteca está a usar a reflexão, irá tomar qualquer tipo e analisá-la 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<CsvRow> 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);
}

Valor 1, verdadeiro

Valor 2, false


Se se quiser ler mais sobre as configurações e possibilidades da biblioteca, pode fazê-lo aqui.

 3
Author: NtFreX, 2018-07-20 20:23:27

Manipulação De Vírgulas

Para manipular vírgulas dentro dos valores ao utilizar string.Format(...), o seguinte funcionou para mim:

var newLine = string.Format("\"{0}\",\"{1}\",\"{2}\"",
                              first,
                              second,
                              third                                    
                              );
csv.AppendLine(newLine);
Então, para combiná-lo com a resposta do Johan, seria assim:
//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());

A devolver o ficheiro CSV

Se você simplesmente queria devolver o arquivo em vez de escrevê-lo para um local, este é um exemplo de como eu consegui:

De um procedimento armazenado

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 uma lista

/* To help illustrate */
public static List<Person> list = new List<Person>();

/* 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 isto seja ... util.
 2
Author: Trevor Nestman, 2016-10-19 17:52:14

Podes ter de adicionar uma linha de alimentação {[[0]}.

 0
Author: OneWileyDog, 2017-09-06 09:13:16

Aqui está outra biblioteca de código aberto para criar arquivos CSV facilmente, Cinchoo ETL

List<dynamic> objs = new List<dynamic>();

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 mais informações, leia por favor o artigo do CodeProject sobre a utilização.

 0
Author: RajN, 2017-10-03 22:04:43

Este é um tutorial simples sobre a criação de arquivos csv usando C# que você será capaz de editar e expandir para atender às suas próprias necessidades.

{[[2]} Primeiro você vai precisar criar uma nova aplicação Visual Studio C# console, há passos a seguir para fazer isso.

O código de exemplo irá criar um ficheiro csv chamado MyTest.csv no local indicado. O conteúdo do arquivo deve ser 3 colunas nomeadas com texto nas primeiras 3 linhas.

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);
        }
    }
}
 0
Author: Bloggins, 2018-04-03 12:55:43

Uma maneira simples de se livrar do problema de substituição é usar File.AppendText para adicionar uma linha no fim do ficheiro 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);
    }
} 
 0
Author: Vinod Srivastav, 2018-06-16 14:43:41
 public void UlozCSV()
    {
        using (StreamWriter pisar = new StreamWriter("zbozi.csv", false, Encoding.Default))
        {// u ukládání nezapomenout - za názvem je FALSE
            pisar.WriteLine(hlavicka); //první řešíme hlavičku csv a následně vypisujeme jednotlivé reproduktory

            foreach (Reproduktor item in list)
            {
                pisar.WriteLine(item.ObjektNaCSVRadek()); //metoda která vypíše podle své třídy
            }
        }
    }
 0
Author: Hos, 2018-09-13 17:26:28