Coder Perfect

In C#, write data to a CSV file.

Problem

I’m attempting to write row per row into a csv file using C#. This is how I work.

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

The entire code is contained within a loop, and each row should be saved to a csv file. In my instance, the following row overwrites the previous row, leaving me with only one record in the csv file, which is the last one. What is the best way to write all the rows in the csv file?

Asked by rampuriyaaa

Solution #1

UPDATE

I proposed doing this manually back in my naive days (it was a simple solution to a simple query), but as this becomes more and more popular, I’d prefer using the package CsvHelper, which performs all of the safety checks, etc.

CSV is a lot more sophisticated than the question and response imply.

Original Answer

Consider doing it this way, because you already have a loop:

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

Or something along those lines. My logic is that you won’t need to write to the file for each item; instead, you’ll simply need to open the stream once and then write to it.

You can replace

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

with

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

if you’d like to maintain prior csv versions in the same file

C# 6

You can accomplish the following if you’re using C# 6.0.

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

EDIT

Here’s a link to a question about what Environment is. NewLine is one of them.

Answered by Johan

Solution #2

I strongly advise you to take the more difficult path. This is especially true if your file is large.

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() creates a new file, fills it with data, and then closes it. Opening files uses a lot more resources than publishing data to an open stream. When a file is opened or closed within a loop, performance suffers.

Johan’s solution solves this problem by storing all of the output in memory and then writing it only once. However, your program will waste a lot of RAM (in the case of large files) and may even crash due to an OutOfMemoryException.

Another benefit of my solution is that it allows you to create pause and resume by preserving the current location in the input data.

upd. Using at the appropriate location

Answered by Pavel Murygin

Solution #3

Because your data may contain commas and newlines, writing csv files by hand might be tricky. Instead, I recommend that you use an existing library.

A few choices are mentioned in this question.

Is there a C# library that reads and writes CSV files?

Answered by Jeppe Andreasen

Solution #4

I like a two-parse solution because it is simple to maintain.

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

Answered by user3495843

Solution #5

Instead of executing AppendAllText() repeatedly, consider opening the file once and then writing the entire content:

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

Answered by Oliver

Post is based on https://stackoverflow.com/questions/18757097/writing-data-into-csv-file-in-c-sharp