9

Alright I want to create a .csv file in C#. I have been looking around and noticed a lot of people are using the system.IO.memorystream and system.io.streamwriter.

The problem is this: I have a web application. I want to give the user the ability to export to excel. Problem is, Excel cannot be installed on the server (don't ask). I want to be able to write an .csv sheet export for a report. Now, the reports headers and data will be different for all of the reports (looping through will solve this). Anybody have an example or better resources for me to go through?

2
  • After reading around. All I really need to do is loop through and output the data separated by commas with /n at the end of the row and keep looping through until done...save the file as .csv and then close the stream...correct? Commented Aug 20, 2010 at 15:52
  • You also need to set the content-type, and if a datum might contain a ", , or newline character you need to escape it too. Code for that in my answer. Commented Aug 20, 2010 at 17:29

7 Answers 7

15

This the approach i normally take. Probably not the most efficient though.

        /// <summary>
    /// Generates the contents of the log file.
    /// </summary>
    /// <returns>The contents of the log file.</returns>
    internal string GenerateLogFile()
    {
        StringBuilder csvExport = new StringBuilder();
        csvExport.AppendLine(Resources.CSVHeader);

        foreach (DataRow row in this.logEntries.Rows)
        {
            csvExport.AppendLine(
                string.Format(
                "\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\", \"{9}\"",
                row[ColumnNames.LogTime], row[ColumnNames.Field1], row[ColumnNames.Field2], row[ColumnNames.Field3], row[ColumnNames.Field4], row[ColumnNames.Field5], row[ColumnNames.Field6], row[ColumnNames.Field7], row[ColumnNames.Field8], row[ColumnNames.Field9]));
        }

        return csvExport.ToString();
    }

    /// <summary>
    /// Adds the CSV file to the response.
    /// </summary>
    /// <param name="csvExportContents">The contents of the CSV file.</param>
    internal void DisplayLogFile(string csvExportContents)
    {
        byte[] data = new ASCIIEncoding().GetBytes(csvExportContents);

        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.ContentType = "APPLICATION/OCTET-STREAM";
        HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=Export.csv");
        HttpContext.Current.Response.OutputStream.Write(data, 0, data.Length);
        HttpContext.Current.Response.End();
    }
Sign up to request clarification or add additional context in comments.

3 Comments

Where does CSVHeader come from?
I don't see how values that might contain " would be escaped.
@RealityDysfunction I'm assuming it's from a resx file. It would be more useful for the sake of the example to just have a string literal.
12
private void WriteItem<T>(StreamWriter sr, T item)
{
    string itemString = item.ToString();
    if(itemString.IndexOfAny(new char[] { '"', ',', '\n', '\r' }) != -1)//skip test and always escape for different speed/filesize optimisation
    {
        sr.Write('"');
        sr.Write(itemString.Replace("\"", "\"\""));
        sr.Write('"');
    }
    else
        sr.Write(itemString);
}
private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line)
{
    bool first = true;
    foreach(T item in line)
    {
        if(!first)
            sr.Write(',');
        first = false;
        WriteItem(sr, item);
    }
}
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines)
{
    bool first = true;
    foreach(IEnumerable<T> line in allLines)
    {
        if(!first)
            sr.Write('\n');
        first = false;
        WriteLine(sr, line);
    }
}
private void WriteCSV<T>(HttpResponse response, IEnumerable<IEnumerable<T>> allLines)
{
    response.ContentType = "text/csv";
    WriteCSV(response.Output, allLines);
}

It can be worth also sending a content-disposition header with a recommended filename.

Edit: Of late, with cases where one needs to interspace an action between items in an enumeration (like the comma and newline above), I've preferred that rather keeping a boolean that keeps being checked, I handle the enumerator directly, and then handle the first element separate from the rest. I started doing this as a micro-opt in a efficiency-push but have grown to just find it a better expression of a code-path that differs for the first item. As such, I'd now write the above as:

private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line)
{
  using(var en = line.GetEnumerator())
  if(en.MoveNext())
  {
    WriteItem(sr, en.Current);
    while(en.MoveNext())
    {
      sr.Write(',');
      WriteItem(sr, en.Current);
    }
}
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines)
{
    using(var en = allLines.GetEnumerator())
    if(en.MoveNext())
    {
      WriteLine(sr, en.Current);
      while(en.MoveNext())
      {
        sr.Write('\n');
        WriteLine(sr, en.Current);
      }
    }
}

1 Comment

practical usage examples would be nice.
4

You should be able to use the examples using System.IO.MemoryStream and System.IO.StreamWriter just fine.

Instead of writing the MemoryStream out to a file, you would return it as the ResponseStream in ASP.NET (making sure that you set the appropriate header values so the browser knows that it's downloading a file).

Comments

4

Excel is only required if you are using Office Interop. Using StringWriter, you are simply going to create a file and add some response information. Excel is only required when opening the file.

Comments

3

There is really no magic in creating a CSV file. The only problem with CSV files is that there is not really a standard, and most importers will just implement one particular behavior for the import process. If you are lucky, you will get something that can guess relatively well.

Generating the CSV file is just a matter of printing the lines. As for the actual details, familiarize yourself with:

http://en.wikipedia.org/wiki/Comma-separated_values

That being said, if what you want is to export to Excel, you could use Microsoft's OOXML SDK:

http://msdn.microsoft.com/en-us/library/bb448854.aspx

The OOXML SDK is a C# library that you can use to generate Excel files on the server. The Brian Jones blog is a great resource on how to use this library:

http://blogs.msdn.com/b/brian_jones/

2 Comments

Do I need Excel on the server for this?
You do not need Excel on the server to run OOXML SDK. In fact, you can even run it on a Linux system with Mono.
3

If you don't mind using a 3rd party library and the LGPL license is okay in your project, then FileHelpers is a great tool for this.

1 Comment

I love FileHelpers! This simple and fast library makes turning flat files into objects easy. It can also turn objects into flat text files in an object oriented way. And it's fast. And it has a wizard to help guide you. Cheers!
2

This is the function used to create csv file:

 private async Task<string> WriteCSV<ViewModel>(IEnumerable<ViewModel> viewModels, string path)
            {
                Type itemType = typeof(ViewModel);
                var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                    .OrderBy(p => p.Name);

                var blobName = string.Empty;

                using (var ms = new MemoryStream())
                {

                    using (var writer = new System.IO.StreamWriter(ms))
                    {
                        writer.WriteLine(string.Join(", ", props.Select(p => p.Name)));

                        foreach (var item in viewModels)
                        {

                            writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null))));
                        }
    }

 }
    }

Otherwise you can refer below link:

https://travelcodingnlotsmore.wordpress.com/2013/06/06/creating-csv-file-from-data-in-list-object-in-c/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.