web-dev-qa-db-fra.com

Écrire des données dans un fichier CSV en C #

J'essaie d'écrire dans un fichier csv ligne par ligne à l'aide du langage C #. Voici ma fonction

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

Toute la fonction est exécutée dans une boucle et chaque ligne doit être écrite dans le fichier csv. Dans mon cas, la ligne suivante écrase la ligne existante et, à la fin, je ne reçois qu'un seul enregistrement dans le fichier csv, qui est le dernier. Comment puis-je écrire toutes les lignes du fichier csv

138
rampuriyaaa

METTRE À JOUR

De retour dans mes jours naïfs, j’ai suggéré de le faire manuellement (c’était une solution simple à une question simple), mais comme cela devient de plus en plus populaire, je recommanderais d’utiliser la bibliothèque CsvHelper les contrôles de sécurité, etc. 

Le format CSV est bien plus compliqué que ne le suggère la question/réponse.

Réponse originale

Comme vous avez déjà une boucle, envisagez de le faire comme ceci:

//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 quelque chose de similaire à cela ... Mon raisonnement est le suivant: vous n'aurez pas besoin d'écrire dans le fichier pour chaque élément, vous n'ouvrirez le flux qu'une seule fois, puis vous l'écrirez.

Vous pouvez remplacer

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

avec 

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

si vous voulez conserver les versions précédentes de csv dans le même fichier

C # 6

Si vous utilisez c # 6.0, vous pouvez effectuer les opérations suivantes

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

MODIFIER

Voici un lien à une question qui explique ce que Environment.NewLine fait

236
Johan

Je vous recommande fortement de choisir la voie la plus fastidieuse. Surtout si votre fichier est volumineux.

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() ouvre un nouveau fichier, écrit le contenu puis ferme le fichier. L’ouverture de fichiers est une opération beaucoup plus lourde en ressources que l’écriture de données dans un flux ouvert. Ouvrir/fermer un fichier dans une boucle entraînera une baisse des performances. 

L'approche suggérée par Johan résout ce problème en stockant toutes les sorties en mémoire, puis en les écrivant une fois. Cependant (dans le cas de gros fichiers), votre programme consommera une grande quantité de RAM et plantera même avec OutOfMemoryException

Un autre avantage de ma solution est que vous pouvez implémenter une pause/reprise en sauvegardant la position actuelle dans les données d'entrée.

upd. Placé en utilisant au bon endroit

71
Pavel Murygin

L'écriture manuelle de fichiers CSV peut s'avérer difficile, car vos données peuvent contenir des virgules et des nouvelles lignes. Je vous suggère d'utiliser une bibliothèque existante à la place. 

Cette question mentionne quelques options.

Y a-t-il des bibliothèques de lecteurs/écrivains CSV en C #?

24
Jeppe Andreasen

J'utilise une solution à deux analyses car il est très facile à maintenir

// 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
user3495843

Utilisez simplement AppendAllText à la place:

File.AppendAllText(filePath, csv);

Le seul inconvénient de AppendAllText est qu'il lève une erreur quand le fichier n'existe pas, il faut donc le vérifier

Désolé, moment blond avant de lire la documentation . Quoi qu'il en soit, la méthode WriteAllText écrase tout ce qui a déjà été écrit dans le fichier, si ce dernier existe.

Notez que votre code actuel n'utilise pas les nouvelles lignes appropriées. Par exemple, dans le Bloc-notes, vous verrez tout cela comme une longue ligne. Changez le code en ceci pour avoir de nouvelles lignes appropriées:

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

Au lieu d'appeler chaque fois AppendAllText(), vous devriez envisager d'ouvrir le fichier une fois, puis d'écrire tout le contenu une fois:

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
Oliver
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();
                    }
                }
            }
        }
    }
}
4
Alejandro Haro

Au lieu de réinventer la roue, une bibliothèque pourrait être utilisée. CsvHelper est idéal pour créer et lire des fichiers CSV. Ses opérations de lecture et d'écriture sont basées sur des flux et prennent donc également en charge les opérations avec une grande quantité de données.


Vous pouvez écrire votre csv comme suit.

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

Comme la bibliothèque utilise la réflexion, elle prend n'importe quel type et l’analyse directement.

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);
}

valeur1, vrai

valeur2, faux


Si vous voulez en savoir plus sur les configurations et les possibilités des bibliothèques, vous pouvez le faire ici .

4
NtFreX

Traitement des virgules

Pour manipuler des virgules à l'intérieur des valeurs lors de l'utilisation de string.Format(...), voici ce qui a fonctionné pour moi:

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

Donc, pour le combiner avec la réponse de Johan, cela ressemblerait à ceci:

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

Retour de fichier CSV

Si vous vouliez simplement renvoyer le fichier au lieu de l'écrire à un emplacement donné, voici un exemple de la façon dont je l'ai accompli:

À partir d'une procédure stockée

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");
}

À partir d'une liste

/* 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");
}

J'espère que cela est utile.

2
Trevor Nestman

Voici une autre bibliothèque open source pour créer facilement un fichier CSV, 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);
}

Pour plus d'informations, consultez l'article CodeProject sur l'utilisation.

0
RajN

C’est un tutoriel simple sur la création de fichiers csv à l’aide de C # que vous pourrez éditer et développer pour répondre à vos besoins.

Pour ce faire, vous devez d’abord créer une nouvelle application console Visual Studio C #.

L'exemple de code créera un fichier csv appelé MyTest.csv à l'emplacement spécifié. Le contenu du fichier doit être composé de 3 colonnes nommées avec du texte dans les 3 premières lignes.

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
Bloggins

Vous devrez peut-être simplement ajouter un saut de ligne "\n\r".

0
OneWileyDog
 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
Hos

Un moyen simple de résoudre le problème de remplacement consiste à utiliser File.AppendText pour ajouter une ligne à la fin du fichier, 

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
Vinod Srivastav