Click here to Skip to main content
15,889,315 members
Articles / Programming Languages / C#
Article

Export a DataSet to Microsoft Excel without the use of COM objects

Rate me:
Please Sign up or sign in to vote.
3.84/5 (84 votes)
28 May 20051 min read 661.4K   120   158
A simple function that writes a DataSet to a Microsoft Excel document.

Introduction

This function takes in a DataSet and file name and writes the DataSet to an Excel worksheet. The code is pretty straightforward. Great thing about this function is that, it's technically an XML file that is saved as an XLS file. So it can be used as either file format. No more leading zero truncation on numbers that look like strings. Example, if you made a tab delimited file and put a field such as "00036" (a field that looks like a number but should be regarded as a string), MS Excel would truncate the leading zeros... This problem is solved with this method.

Here is the code:

C#
public static void exportToExcel(DataSet source, string fileName)

{

    System.IO.StreamWriter excelDoc;

    excelDoc = new System.IO.StreamWriter(fileName);
    const string startExcelXML = "<xml version>\r\n<Workbook " + 
          "xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\r\n" + 
          " xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n " + 
          "xmlns:x=\"urn:schemas-    microsoft-com:office:" + 
          "excel\"\r\n xmlns:ss=\"urn:schemas-microsoft-com:" + 
          "office:spreadsheet\">\r\n <Styles>\r\n " + 
          "<Style ss:ID=\"Default\" ss:Name=\"Normal\">\r\n " + 
          "<Alignment ss:Vertical=\"Bottom\"/>\r\n <Borders/>" + 
          "\r\n <Font/>\r\n <Interior/>\r\n <NumberFormat/>" + 
          "\r\n <Protection/>\r\n </Style>\r\n " + 
          "<Style ss:ID=\"BoldColumn\">\r\n <Font " + 
          "x:Family=\"Swiss\" ss:Bold=\"1\"/>\r\n </Style>\r\n " + 
          "<Style     ss:ID=\"StringLiteral\">\r\n <NumberFormat" + 
          " ss:Format=\"@\"/>\r\n </Style>\r\n <Style " + 
          "ss:ID=\"Decimal\">\r\n <NumberFormat " + 
          "ss:Format=\"0.0000\"/>\r\n </Style>\r\n " + 
          "<Style ss:ID=\"Integer\">\r\n <NumberFormat " + 
          "ss:Format=\"0\"/>\r\n </Style>\r\n <Style " + 
          "ss:ID=\"DateLiteral\">\r\n <NumberFormat " + 
          "ss:Format=\"mm/dd/yyyy;@\"/>\r\n </Style>\r\n " + 
          "</Styles>\r\n ";
     const string endExcelXML = "</Workbook>";

     int rowCount = 0;
     int sheetCount = 1;
     /*
    <xml version>
    <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
    xmlns:o="urn:schemas-microsoft-com:office:office"
    xmlns:x="urn:schemas-microsoft-com:office:excel"
    xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
    <Styles>
    <Style ss:ID="Default" ss:Name="Normal">
      <Alignment ss:Vertical="Bottom"/>
      <Borders/>
      <Font/>
      <Interior/>
      <NumberFormat/>
      <Protection/>
    </Style>
    <Style ss:ID="BoldColumn">
      <Font x:Family="Swiss" ss:Bold="1"/>
    </Style>
    <Style ss:ID="StringLiteral">
      <NumberFormat ss:Format="@"/>
    </Style>
    <Style ss:ID="Decimal">
      <NumberFormat ss:Format="0.0000"/>
    </Style>
    <Style ss:ID="Integer">
      <NumberFormat ss:Format="0"/>
    </Style>
    <Style ss:ID="DateLiteral">
      <NumberFormat ss:Format="mm/dd/yyyy;@"/>
    </Style>
    </Styles>
    <Worksheet ss:Name="Sheet1">
    </Worksheet>
    </Workbook>
    */
    excelDoc.Write(startExcelXML);
    excelDoc.Write("<Worksheet ss:Name=\"Sheet" + sheetCount + "\">");
    excelDoc.Write("<Table>");
    excelDoc.Write("<Row>");
    for(int x = 0; x < source.Tables[0].Columns.Count; x++)
    {
      excelDoc.Write("<Cell ss:StyleID=\"BoldColumn\"><Data ss:Type=\"String\">");
      excelDoc.Write(source.Tables[0].Columns[x].ColumnName);
      excelDoc.Write("</Data></Cell>");
    }
    excelDoc.Write("</Row>");
    foreach(DataRow x in source.Tables[0].Rows)
    {
      rowCount++;
      //if the number of rows is > 64000 create a new page to continue output
      if(rowCount==64000) 
      {
        rowCount = 0;
        sheetCount++;
        excelDoc.Write("</Table>");
        excelDoc.Write(" </Worksheet>");
        excelDoc.Write("<Worksheet ss:Name=\"Sheet" + sheetCount + "\">");
        excelDoc.Write("<Table>");
      }
      excelDoc.Write("<Row>"); //ID=" + rowCount + "
      for(int y = 0; y < source.Tables[0].Columns.Count; y++)
      {
        System.Type rowType;
        rowType = x[y].GetType();
        switch(rowType.ToString())
        {
          case "System.String":
             string XMLstring = x[y].ToString();
             XMLstring = XMLstring.Trim();
             XMLstring = XMLstring.Replace("&","&");
             XMLstring = XMLstring.Replace(">",">");
             XMLstring = XMLstring.Replace("<","<");
             excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" + 
                            "<Data ss:Type=\"String\">");
             excelDoc.Write(XMLstring);
             excelDoc.Write("</Data></Cell>");
             break;
           case "System.DateTime":
             //Excel has a specific Date Format of YYYY-MM-DD followed by  
             //the letter 'T' then hh:mm:sss.lll Example 2005-01-31T24:01:21.000
             //The Following Code puts the date stored in XMLDate 
             //to the format above
             DateTime XMLDate = (DateTime)x[y];
             string XMLDatetoString = ""; //Excel Converted Date
             XMLDatetoString = XMLDate.Year.ToString() +
                  "-" + 
                  (XMLDate.Month < 10 ? "0" + 
                  XMLDate.Month.ToString() : XMLDate.Month.ToString()) +
                  "-" +
                  (XMLDate.Day < 10 ? "0" + 
                  XMLDate.Day.ToString() : XMLDate.Day.ToString()) +
                  "T" +
                  (XMLDate.Hour < 10 ? "0" + 
                  XMLDate.Hour.ToString() : XMLDate.Hour.ToString()) +
                  ":" +
                  (XMLDate.Minute < 10 ? "0" + 
                  XMLDate.Minute.ToString() : XMLDate.Minute.ToString()) +
                  ":" +
                  (XMLDate.Second < 10 ? "0" + 
                  XMLDate.Second.ToString() : XMLDate.Second.ToString()) + 
                  ".000";
                excelDoc.Write("<Cell ss:StyleID=\"DateLiteral\">" + 
                             "<Data ss:Type=\"DateTime\">");
                excelDoc.Write(XMLDatetoString);
                excelDoc.Write("</Data></Cell>");
                break;
              case "System.Boolean":
                excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" + 
                            "<Data ss:Type=\"String\">");
                excelDoc.Write(x[y].ToString());
                excelDoc.Write("</Data></Cell>");
                break;
              case "System.Int16":
              case "System.Int32":
              case "System.Int64":
              case "System.Byte":
                excelDoc.Write("<Cell ss:StyleID=\"Integer\">" + 
                        "<Data ss:Type=\"Number\">");
                excelDoc.Write(x[y].ToString());
                excelDoc.Write("</Data></Cell>");
                break;
              case "System.Decimal":
              case "System.Double":
                excelDoc.Write("<Cell ss:StyleID=\"Decimal\">" + 
                      "<Data ss:Type=\"Number\">");
                excelDoc.Write(x[y].ToString());
                excelDoc.Write("</Data></Cell>");
                break;
              case "System.DBNull":
                excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" + 
                      "<Data ss:Type=\"String\">");
                excelDoc.Write("");
                excelDoc.Write("</Data></Cell>");
                break;
              default:
                throw(new Exception(rowType.ToString() + " not handled."));
            }
          }
          excelDoc.Write("</Row>");
        }
        excelDoc.Write("</Table>");
        excelDoc.Write(" </Worksheet>");
        excelDoc.Write(endExcelXML);
        excelDoc.Close();
    }

Note

To see what generated, just pass the file name with a .txt extension. For Excel format, the file name will be .xls. For XML format, the file name will be .xml.

The Export Routine does have one side effect! (if anyone can figure out a solution to this, it would be greatly appreciated). The file is saved as an .XLS file, but it technically is still an XML file. This little nuance makes the file size larger then it really should be. A quick fix to this is to just do File Save As.... after the file has been exported. When you do the Save As in Excel, it will reconstruct it as a "real" Excel file, and it will bring the file size down to what it should be.

Feed Back is always welcome.

Simple as that...Enjoy.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Help in Data > 64000 rows Pin
oobject1-Sep-06 1:50
oobject1-Sep-06 1:50 
QuestionOpens as XML document not as Excel Pin
vikkyzkool9-May-06 2:47
vikkyzkool9-May-06 2:47 
AnswerRe: Opens as XML document not as Excel Pin
Xodiak9-May-06 4:23
Xodiak9-May-06 4:23 
QuestionRe: Opens as XML document not as Excel Pin
vikkyzkool9-May-06 6:30
vikkyzkool9-May-06 6:30 
QuestionRe: Opens as XML document not as Excel Pin
unRheal1-Dec-06 8:10
unRheal1-Dec-06 8:10 
GeneralFormattin Problem Pin
TuneFish4-Mar-06 5:06
TuneFish4-Mar-06 5:06 
GeneralRe: Formattin Problem Pin
Xodiak4-Mar-06 11:50
Xodiak4-Mar-06 11:50 
GeneralWriting the binary excel file instead of xml [modified] Pin
sanjeevofbcs2-Feb-06 21:39
sanjeevofbcs2-Feb-06 21:39 
The solution given in this article generates an xml file which is understood by excel application. It doesn't generates a excel file in binary format. To do so you need to do "Save as" while file is open in excel application, and choose appropriate file type.

If you want to generate excel-binary file programaticaly then here is the code. Just call exportToExcel(dataset, filePath), where dataset is the DataSet containing data for which excel file has to be generated, and filePath is the string containing complete filePath where the file should be generated.



using System;<br />
using System.IO;<br />
using System.Collections;<br />
using System.Data;<br />
using System.Text;<br />
using System.Data.OleDb;<br />
<br />
private static  OleDbConnection GetConnection(string filePath ) <br />
  {<br />
   return new System.Data.OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";Extended Properties=\"Excel 8.0;HDR=YES;\"");<br />
  }<br />
<br />
  public static void exportToExcel(DataTable dt, string fileName)<br />
  {<br />
   #region initialization<br />
   //if the file already exists then delete it<br />
   System.IO.FileInfo fi = new System.IO.FileInfo(fileName);<br />
   if (fi.Exists)<br />
   {<br />
    fi.Delete();<br />
   }<br />
   <br />
   //set the table name if its not there<br />
   if (dt.TableName == string.Empty)<br />
   {<br />
    dt.TableName = "Sheet1";<br />
   }<br />
   else//remove $ from table name if it is there<br />
   {<br />
    dt.TableName = dt.TableName.Replace("$",string.Empty);<br />
   }<br />
   #endregion<br />
<br />
   <br />
   string sql = GetTableCreationSql(dt);<br />
   OleDbConnection connection =  GetConnection(fileName);<br />
   OleDbCommand command = new OleDbCommand();<br />
   command.Connection = connection;<br />
   try<br />
   {<br />
    #region Create table<br />
    command.CommandText = GetTableCreationSql(dt);<br />
    command.Connection.Open();<br />
    command.ExecuteNonQuery();<br />
    #endregion<br />
    <br />
    #region Insert Into Table<br />
    <br />
    command.CommandText = GetInsertSql(dt);<br />
<br />
    foreach(DataRow row in dt.Rows)<br />
    {<br />
     SetParametersInCommand(row, command);<br />
     command.ExecuteNonQuery();<br />
    }<br />
    <br />
    #endregion<br />
   }<br />
   finally<br />
   {<br />
    command.Connection.Close();<br />
   }<br />
<br />
  }<br />
<br />
 <br />
<br />
  /// <summary><br />
  /// form a string which should be the sqlCommand for creating Table in oleDB<br />
  /// </summary><br />
  /// <param name="dt"></param><br />
  /// <returns>create table [tableName] ( Column1 type, ..., Columnn Type)</returns><br />
  private static string GetTableCreationSql(DataTable dt)<br />
  {<br />
   StringBuilder sqlBuilder = new StringBuilder();<br />
   sqlBuilder.Append("create table [");<br />
   sqlBuilder.Append(dt.TableName);<br />
   sqlBuilder.Append( "] ( " );<br />
<br />
   #region Get Column List<br />
   //Create a list of column names and their data types, e.g<br />
   //[ColumnName1] nvarchar, [ColumnName2] nvarchar,...[ColumnNamen] nvarchar<br />
   foreach(DataColumn col in dt.Columns)<br />
   {<br />
    if (col.Ordinal== 0)<br />
     sqlBuilder.Append( "[" );<br />
    else<br />
     sqlBuilder.Append( ", [" );<br />
<br />
    sqlBuilder.Append(col.ColumnName.Trim());<br />
    sqlBuilder.Append("] nvarchar");<br />
   }<br />
   #endregion<br />
<br />
   sqlBuilder.Append(" )"); <br />
<br />
   return sqlBuilder.ToString();<br />
  }<br />
<br />
  /// <summary><br />
  /// form a insert statement to insert data into oleDB<br />
  /// </summary><br />
  /// <param name="dt"></param><br />
  /// <returns>Insert Into tableName ([ColumnName1], [ColumnName2] ,...[ColumnNamen]) values (?,?,..,?) </returns><br />
  private static string GetInsertSql(DataTable dt)<br />
  {<br />
   StringBuilder sqlBuilder = new StringBuilder();<br />
   StringBuilder paramMarks = new StringBuilder();<br />
   sqlBuilder.Append("Insert Into [");<br />
   sqlBuilder.Append(dt.TableName);<br />
   sqlBuilder.Append( "] ( " );<br />
<br />
<br />
   #region Get Column List<br />
   //Create a list of column names and their place holders<br />
   //[ColumnName1] , [ColumnName2] ,...[ColumnNamen] <br />
   // ?,?,...?<br />
   foreach(DataColumn col in dt.Columns)<br />
   {<br />
    if (col.Ordinal == 0)<br />
    {<br />
     sqlBuilder.Append( "[" );<br />
     paramMarks.Append( "?" );<br />
    }<br />
    else<br />
    {<br />
     sqlBuilder.Append( ", [");<br />
     paramMarks.Append(",?");<br />
    }<br />
<br />
    sqlBuilder.Append(col.ColumnName.Trim());<br />
    sqlBuilder.Append( "] " );<br />
   }<br />
   #endregion<br />
<br />
   sqlBuilder.Append(" ) values ("); <br />
   sqlBuilder.Append(paramMarks.ToString() );<br />
   sqlBuilder.Append( ")" );<br />
<br />
   return sqlBuilder.ToString();<br />
  }<br />
<br />
<br />
  private static void SetParametersInCommand(DataRow row, OleDbCommand command)<br />
  {<br />
   UnicodeEncoding en = new UnicodeEncoding();<br />
   string argumentName= string.Empty;<br />
   int index = 0;<br />
   command.Parameters.Clear();<br />
   foreach(DataColumn col in row.Table.Columns)<br />
   {<br />
    argumentName = "@Args" + index;<br />
    command.Parameters.Add( new OleDbParameter(argumentName, OleDbType.VarBinary)).Value = <br />
     en.GetBytes(row[ col ].ToString());<br />
    index++;<br />
   }   <br />
  }


Sanjeev Kumar Singh,(sanjeevofbcs@hotmail.com)

modified on Friday, April 17, 2009 4:51 AM

QuestionRe: Writing the binary excel file instead of xml Pin
vikkyzkool9-May-06 2:40
vikkyzkool9-May-06 2:40 
AnswerRe: Writing the binary excel file instead of xml Pin
sanjeevofbcs9-May-06 19:38
sanjeevofbcs9-May-06 19:38 
GeneralHow come I get a single quatation mark in front of each Excel column Pin
pdz5-Sep-06 17:41
pdz5-Sep-06 17:41 
GeneralRe: Writing the binary excel file instead of xml Pin
eospon18-Oct-06 14:05
eospon18-Oct-06 14:05 
GeneralRe: Writing the binary excel file instead of xml Pin
mikedepetris5-Mar-09 4:12
mikedepetris5-Mar-09 4:12 
GeneralRe: Writing the binary excel file instead of xml [modified] Pin
sanjeevofbcs16-Apr-09 22:51
sanjeevofbcs16-Apr-09 22:51 
GeneralRe: Writing the binary excel file instead of xml Pin
kuklei5-Jul-10 12:56
kuklei5-Jul-10 12:56 
GeneralNice Pin
Anonymous23-Sep-05 11:05
Anonymous23-Sep-05 11:05 
GeneralRe: Nice Pin
Xodiak28-Sep-05 4:21
Xodiak28-Sep-05 4:21 
GeneralRe: Nice Pin
nsimeonov10-Nov-05 13:13
nsimeonov10-Nov-05 13:13 
GeneralAdded a foreach statement to handle multiple tables Pin
Valkyrie-MT22-Aug-05 10:41
Valkyrie-MT22-Aug-05 10:41 
GeneralFrom Author: Error In Code that and I cant update it Pin
Xodiak3-Jul-05 6:47
Xodiak3-Jul-05 6:47 
Generalalternative way Pin
Anonymous17-Jun-05 1:09
Anonymous17-Jun-05 1:09 
GeneralRe: alternative way Pin
nsimeonov15-Nov-05 6:32
nsimeonov15-Nov-05 6:32 
GeneralGood start Pin
SimonS15-Feb-05 4:27
SimonS15-Feb-05 4:27 
GeneralRe: Good start Pin
Ashley van Gerven29-Mar-05 21:39
Ashley van Gerven29-Mar-05 21:39 
GeneralRe: Good start Pin
Jazzynupe26-May-05 5:55
Jazzynupe26-May-05 5:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.