Click here to Skip to main content
Click here to Skip to main content

Generate Excel files without using Microsoft Excel

By , 22 Jun 2011
 

Introduction

Generating Excel files from web pages or other applications is a major subject in many articles. I'd like to present here a solution that does not require MS Excel to be installed on the target computer. This article shows how to create Microsoft Excel Binary Interchange File Format (BIFF) without using Microsoft Excel. BIFF is the native file format for Excel data, and can be viewed and modified in Microsoft Excel 97 or later.

Approaches and problems

The technique that is most frequently used to transfer data to an Excel workbooks is Automation. With Automation, you can call methods and properties that are specific to Excel tasks, but this solution has many drawbacks. Some of them are described in the Microsoft Knowledge Base. Additionally, you have to manage the lifetime of the temporary XLS files created on the server. Also, it is slow, because Excel runs in a separate process.

ExcelWriter class

The solution presented here is to write directly to a stream in Excel binary file format. For this purpose, I created very small C# class called ExcelWriter.

ExcelWriter class diagram
/// <summary>
/// Produces Excel file without using Excel
/// </summary>
public class ExcelWriter
{
    private Stream stream;
    private BinaryWriter writer;

    private ushort[] clBegin = { 0x0809, 8, 0, 0x10, 0, 0 };
    private ushort[] clEnd = { 0x0A, 00 };


    private void WriteUshortArray(ushort[] value)
    {
        for (int i = 0; i < value.Length; i++)
            writer.Write(value[i]);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ExcelWriter"/> class.
    /// </summary>
    /// <param name="stream">The stream.</param>
    public ExcelWriter(Stream stream)
    {
        this.stream = stream;
        writer = new BinaryWriter(stream);
    }

    /// <summary>
    /// Writes the text cell value.
    /// </summary>
    /// <param name="row">The row.</param>
    /// <param name="col">The col.</param>
    /// <param name="value">The string value.</param>
    public void WriteCell(int row, int col, string value)
    {
        ushort[] clData = { 0x0204, 0, 0, 0, 0, 0 };
        int iLen = value.Length;
        byte[] plainText = Encoding.ASCII.GetBytes(value);
        clData[1] = (ushort)(8 + iLen);
        clData[2] = (ushort)row;
        clData[3] = (ushort)col;
        clData[5] = (ushort)iLen;
        WriteUshortArray(clData);
        writer.Write(plainText);
    }

    /// <summary>
    /// Writes the integer cell value.
    /// </summary>
    /// <param name="row">The row number.</param>
    /// <param name="col">The column number.</param>
    /// <param name="value">The value.</param>
    public void WriteCell(int row, int col, int value)
    {
        ushort[] clData = { 0x027E, 10, 0, 0, 0 };
        clData[2] = (ushort)row;
        clData[3] = (ushort)col;
        WriteUshortArray(clData);
        int iValue = (value << 2) | 2;
        writer.Write(iValue);
    }

    /// <summary>
    /// Writes the double cell value.
    /// </summary>
    /// <param name="row">The row number.</param>
    /// <param name="col">The column number.</param>
    /// <param name="value">The value.</param>
    public void WriteCell(int row, int col, double value)
    {
        ushort[] clData = { 0x0203, 14, 0, 0, 0 };
        clData[2] = (ushort)row;
        clData[3] = (ushort)col;
        WriteUshortArray(clData);
        writer.Write(value);
    }

    /// <summary>
    /// Writes the empty cell.
    /// </summary>
    /// <param name="row">The row number.</param>
    /// <param name="col">The column number.</param>
    public void WriteCell(int row, int col)
    {
        ushort[] clData = { 0x0201, 6, 0, 0, 0x17 };
        clData[2] = (ushort)row;
        clData[3] = (ushort)col;
        WriteUshortArray(clData);
    }

    /// <summary>
    /// Must be called once for creating XLS file header
    /// </summary>
    public void BeginWrite()
    {
        WriteUshortArray(clBegin);
    }

    /// <summary>
    /// Ends the writing operation, but do not close the stream
    /// </summary>
    public void EndWrite()
    {
        WriteUshortArray(clEnd);
        writer.Flush();
    }
}

Using the code

The ExcelWriter sample is a console application that writes an XLS file to the name and location specified. The XLS file that is created is simply an empty spreadsheet. Then, you can start to write cell values by calling the WriteCell method with the row number, column number, and a cell value as parameters:

namespace XLSExportDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            FileStream stream = new FileStream("demo.xls", FileMode.OpenOrCreate);
            ExcelWriter writer = new ExcelWriter(stream);
            writer.BeginWrite();
            writer.WriteCell(0, 0, "ExcelWriter Demo");
            writer.WriteCell(1, 0, "int");
            writer.WriteCell(1, 1, 10);
            writer.WriteCell(2, 0, "double");
            writer.WriteCell(2, 1, 1.5);
            writer.WriteCell(3, 0, "empty");
            writer.WriteCell(3, 1);
            writer.EndWrite();
            stream.Close();
        }
    }
}

The picture below shows the final result of this sample:

The ExcelWriter class supports numeric and text values for the cells, and can be used for exporting data from the database to an XLS file, or for producing an XLS stream from a website on the fly.

I hope this article gives you a head start in working with Excel files from .NET and C#.

History

  • 03 March 2009 - Initial submission.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Serhiy Perevoznyk
Architect
Belgium Belgium
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalvery cool stuffmemberJerry139 May '13 - 2:31 
Smile | :)
So much time, but so little things I have to do.

QuestionI can't open the generated XLS file through Excel 2010memberJosen.L.Zhang9 Apr '13 - 0:03 
When i double click the XLS file, it told me : The file corrupt and cannot be opened.
AnswerRe: I can't open the generated XLS file through Excel 2010membersangheraajit14 Apr '13 - 22:04 
Do you got any fix for this.
Ajit Sanghera

Software Engineer
e-Soft Technologies
449 Oshiwara Industrial Estate,
Opp. Oshiwara Bus Depo,
Goregaon (w),
Mumbai 400104
ajit@esoftech.com

GeneralMy vote of 5memberDineshMaind5 Mar '13 - 6:01 
Awesome API...
QuestionPlease add Border Style at next upgradememberphong104057224 Jan '13 - 16:29 
This is great tool to export excel from Database or DataTable but please add Border Style of cell at next upgrade!
Thanks
SuggestionColumn Width AutoFit?mvpadriancs9 Jan '13 - 14:46 
Is it possible to make a Column Width AutoFit? Smile | :)
Something like:
public void ColumnWidthAutoFit(int column)
{
    ...
}

SuggestionCode Patch, Write DataTable [modified]mvpadriancs9 Jan '13 - 14:01 
code patch:
void WriteCell(System.Data.DataTable dt)
{
    WriteCell(0, 0, dt, true);
}
void WriteCell(int x, int y, System.Data.DataTable dt, bool writeTableHeader)
{
    if (writeTableHeader)
    {
        for (int i = 0; i < dt.Columns.Count; i++)
        {
            WriteCell(y, x + i, dt.Columns[i].ColumnName);
        }
        y = y + 1;
    }
 
    for (int i = 0; i < dt.Rows.Count; i++)
    {
        for (int j = 0; j < dt.Columns.Count; j++)
        {
            WriteCell(x + i, y + j, dt.Rows[i][j]);
        }
    }
}


modified 9 Jan '13 - 20:38.

QuestionIs it possible to Write stream to respose headers instead of a demo.xls file?membershabari713 Dec '12 - 0:25 
Is it possible to Write stream to respose headers instead of a demo.xls file?So, that an Open/save dialog would pop up
QuestionMore feature rich alternativememberAndrew Kirillov11 Nov '12 - 22:30 
NPOI[^] does the same, but provides much more features. Just in case of an interest ...
With best regards,
Andrew Kirillov
AForge.NET

AnswerRe: More feature rich alternativememberMember 940799029 Mar '13 - 16:58 
Upvoting this one for sure.   I don't know why, but the majority of solutions being presented on the net (even the prestigious StackOverflow) seem entirely worthless.
 
Apache's POI is reputable.   Use that.   Ignore everything else aside from Automation.
QuestionMultiple SheetsmemberMember 810781128 Oct '12 - 16:09 
Is it possible to use this if I need to save an excel file with multiple sheets?
Questionlimited to 255 chars per cell. how we can increase the limit ..?memberaisoft19 Oct '12 - 5:50 
limited to 255 chars per cell. how we can increase the limit ..?
QuestionGenerating Excelmembernirajzambad7 Aug '12 - 3:03 
What if i dont want to create new instance of excel sheet and write to the previous excel file
and to the next row where i stopped last time
GeneralMy vote of 5memberHuỳnh Hữu Ân24 Jul '12 - 18:06 
This excellent. Now i can export data to excel without microsoft com or oledb! bd
QuestionThe generated xls file could not be read by OLEDBmemberdaiwuju4 Jul '12 - 22:57 
DataTable dataTable_Excel;
string strExcelFile = FileOpen;
strExcelFile = string.Format("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = {0}; Extended Properties = \"Excel 8.0; HDR = Yes; IMEX = 1\";",strExcelFile);
OleDbConnection conOLDB = new OleDbConnection(strExcelFile);
conOLDB.Open();
DataTable dataTable_ExcelSheet = conOLDB.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string sheetName = dataTable_ExcelSheet.Rows[0]["TABLE_NAME"].ToString().Trim();
string selectstr = string.Format("SELECT * FROM [{0}]", sheetName);
OleDbCommand selectCommand = new OleDbCommand(selectstr, conOLDB);
OleDbDataAdapter daExcel = new OleDbDataAdapter();
daExcel.SelectCommand = selectCommand;
daExcel.Fill(dataTable_Excel);
conOLDB.Close();
conOLDB.Dispose();
QuestionA minor problem in Chinese Fontmemberdaiwuju29 Jun '12 - 19:05 
When I set private Font defaultFont = new Font("宋体", 10), the font shows in the excel is '??'.
QuestionMere cellsmemberdaniloao31 May '12 - 13:50 
Can I merge cells?
QuestionBordersmemberMember 901259929 May '12 - 6:49 
Hello all,
 
So far this works great. Formatting and file creation can be done with ease. However, I notice that this does not have option to make border (e.g. for creating table on a worksheet). Am I missing something or is there really not a way to set the border settings for each cell?
 
Thank you for your help
QuestionMore Than one WorkSheetmemberhichamveo24 May '12 - 6:57 
Hi,
thanks for this good article.But i want to add more than one worksheet by xls file.
any idea about this need?thanks
sdfrt

QuestionGreat work!!memberCurtCobrain7 Apr '12 - 4:57 
Thank you very much !!
GeneralMy vote of 5memberMikhail Tsennykh (devnoob)19 Mar '12 - 8:50 
Awesome, thank you!
QuestionCreating .XLSX filememberbhavtosh.sharma2 Mar '12 - 0:57 
hi,
firstly, a very handy way of creating excel on the fly. i tried your solution to create excel 2010 format as .XLSX file which was saved but while opening it, excel didnt open it as there was an error saying the file format is not same as per the .xlsx extension...
 
any view to share...
Thanks and Good Day,
Bhavtosh

AnswerRe: Creating .XLSX filememberdaiwuju29 Jun '12 - 19:00 
Maybe you could have a look at this: http://lateral8.com/articles/2010/3/5/openxml-sdk-20-export-a-datatable-to-excel.aspx[^]
QuestionProtected Viewmemberccchg9 Feb '12 - 0:22 
This is a very interesting way to generate Excel. However, I encounter problem when opening the generated Excel file with Protected View restriction. I opened the generated file using Microsoft Office 2010.
 
When I enable "Excel 3 Worksheets" to open as normal rather than in Protected View, then I do not face Protected View restriction message anymore.
 
Does it any excel version or file type specify in the code? How shall we able to generate the Excel with later version to avoid Protected View restriction?
 
Thank you
QuestionSpecial characters are not comingmemberiliyash11 Jan '12 - 4:37 
I have data which have some special characters. while writing the data in cell all these characters converted to " ?".
Please give the solution for this type of data.

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 22 Jun 2011
Article Copyright 2009 by Serhiy Perevoznyk
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid