views:

173

answers:

6

if i have a list of objects called "Car"

public class Car
{
     public string Name;
     public int Year;
     public string Model;
}

and i have a list of List and i want to generate a csv file dynamically from this list

+1  A: 

Look at the FileHelpers library.

From the site:

The FileHelpers are a free and easy to use .NET library to import/export data from fixed length or delimited records in files, strings or streams.

This will make sure that all kinds of gotchas in line termination, escaping and such are handled correctly, as per RFC-4180.

Oded
+3  A: 
  1. FileHelpers Library
  2. Text OleDb Provider
  3. Manual via String concatenation according to RFC-4180
  4. Third party library, for example Aspose.Cell can do it without any friction from you. And it is very fast.
Sergey Mirvoda
+1 for the link to the RFC! There's also a nice reference on Wikipedia: http://en.wikipedia.org/wiki/Comma-separated_values
TrueWill
A: 

Use StringBuilder..

   var sb = new StringBuilder();
   foreach(var o in objects)
     sb.Append(string.format("Name:{0} Year:{1} Model{2},", 
                  o.Name, o.Year, o.Model));
   var csv = sb.ToString(0, sb.Length - 1);

If you overrde ToString() appropriately in the Car class all you need is:

   var sb = new StringBuilder();
   foreach(var o in objects)
      sb.Append(string.format("{0},", o)); 
   var csv = sb.ToString(0, sb.Length - 1);
Charles Bretana
what about newline and commas in string values?
Sergey Mirvoda
deal with them... Do you expect every answer to examine and address every possible twist and turn? ... and include the complete code which deals with each of them?
Charles Bretana
no, but only hard task in csv exporting is dealing with edge cases. string concatenation is straightforward.
Sergey Mirvoda
A: 

Putting together comma-separated values I always like to point at the much underrated string.Join(string separator, string[] elements) static method, but if there are helper libraries out there, that's probably better stuff.

flq
A: 

add the following method to Car:

String Escape(String s)
{
    StringBuilder sb = new StringBuilder();
    bool needQuotes = false;
    foreach (char c in s.ToArray())
    {
        switch (c)
        {
            case '"': sb.Append("\\\""); needQuotes = true; break;
            case ' ': sb.Append(" "); needQuotes = true; break;
            case ',': sb.Append(","); needQuotes = true; break;
            case '\t': sb.Append("\\t"); needQuotes = true; break;
            case '\n': sb.Append("\\n"); needQuotes = true; break;
            default: sb.Append(c); break;
        }
    }
    if (needQuotes)
        return "\"" + sb.ToString() + "\"";
    else
        return sb.ToString();
}

public void SerializeAsCsv(Stream stream)
{
    stream.Write(Escape(Name));
    stream.Write(",");
    stream.Write(Year.ToString());
    stream.Write(",");
    stream.Write(Escape(Model));
    stream.Write("\n");
}

Now you can serialize the whole list:

foreach (Car car in list)
{
    car.SerializeAsCsv(stream);
}
Vlad
A: 

I'd implement some addtional serialzation behaviors as per this article. If you want to get fancy, you can create a setting in your projects properties. This setting would determine if your class used csv or default serialialization. You'd then access it through the techniques shown here. Consider using a static constructor to read appsettings and make a boolean value accessable to your serialization code. Vlads' code looks great, just plug it in to your code. Also you can consider other, maybe more desirable ways to change your serialzation behavior.

Or Create an interface called 'SerializeAsCSV' and use it kind of like this:

// Partial Contents of MyCoolClass.csv:

   public class MyCoolClass : ISerializeAsCSV, IDisposable
   {

      protected static bool serializesToCSV = false;


      static MyCoolClass()
      {
         serializesToCSV = 
            (typeof(MyCoolClass).GetInterface("GrooveySoft.Shared.Interfaces.ISerializeAsCSV") == null)
            ? false
            : true;

      }


      public MyCoolClass(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
      {
        // your stuff here
      }

      public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
      {
         // your stuff here
      }

    }

// contents of ISerializeAsCSV.cs

using System.Runtime.Serialization;

namespace GrooveySoft.Shared.Interfaces
{
   /// <summary>
   /// indicates that implementor will serialize to csv format
   /// </summary>
   public interface ISerializeAsCSV : ISerializable
   {
   }
}

This should get your started . . . I haven't compiled and tested this . . but you get the general idea.

TheEruditeTroglodyte