Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing data into CSV file in C#

Tags:

c#

file

csv

People also ask

How do I write data into a CSV file?

Steps for writing a CSV file First, open the CSV file for writing ( w mode) by using the open() function. Second, create a CSV writer object by calling the writer() function of the csv module. Third, write data to CSV file by calling the writerow() or writerows() method of the CSV writer object.

How do I save a CSV file in C#?

ToString(); string csv = string. Format("{0},{1}\n", first, second); File. WriteAllText(filePath, csv); The whole function runs inside a loop, and every row should be written to the csv file.


UPDATE

Back in my naïve days, I suggested doing this manually (it was a simple solution to a simple question), however due to this becoming more and more popular, I'd recommend using the library CsvHelper that does all the safety checks, etc.

CSV is way more complicated than what the question/answer suggests.

Original Answer

As you already have a loop, consider doing it like this:

//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 to this effect. My reasoning is: you won't be need to write to the file for every item, you will only be opening the stream once and then writing to it.

You can replace

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

with

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

if you want to keep previous versions of csv in the same file

C# 6

If you are using c# 6.0 then you can do the following

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

EDIT

Here is a link to a question that explains what Environment.NewLine does.


I would highly recommend you to go the more tedious route. Especially if your file size 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() opens a new file, writes the content and then closes the file. Opening files is a much resource-heavy operation, than writing data into open stream. Opening\closing a file inside a loop will cause performance drop.

The approach suggested by Johan solves that problem by storing all the output in memory and then writing it once. However (in case of big files) you program will consume a large amount of RAM and even crash with OutOfMemoryException

Another advantage of my solution is that you can implement pausing\resuming by saving current position in input data.

upd. Placed using in the right place


Writing csv files by hand can be difficult because your data might contain commas and newlines. I suggest you use an existing library instead.

This question mentions a few options.

Are there any CSV readers/writer libraries in C#?


I use a two parse solution as it's very easy 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());

Instead of calling every time AppendAllText() you could think about opening the file once and then write the whole content once:

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

You can use AppendAllText instead:

File.AppendAllText(filePath, csv);

As the documentation of WriteAllText says:

If the target file already exists, it is overwritten

Also, note that your current code is not using proper new lines, for example in Notepad you'll see it all as one long line. Change the code to this to have proper new lines:

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

Instead of reinventing the wheel a library could be used. CsvHelper is great for creating and reading csv files. It's read and write operations are stream based and therefore also support operations with a big amount of data.


You can write your csv like the following.

using(var textWriter = new StreamWriter(@"C:\mypath\myfile.csv"))
{
    var writer = new CsvWriter(textWriter, CultureInfo.InvariantCulture);
    writer.Configuration.Delimiter = ",";

    foreach (var item in list)
    {
        writer.WriteField( "a" );
        writer.WriteField( 2 );
        writer.WriteField( true );
        writer.NextRecord();
    }
}

As the library is using reflection it will take any type and parse it directly.

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, CultureInfo.InvariantCulture);
    writer.Configuration.Delimiter = ",";
    writer.WriteRecords(rows);
}

value1,true

value2,false


If you want to read more about the librarys configurations and possibilities you can do so here.