As I needed to export some data to an xlsx (Excel 2007+) file.
I first used the Microsoft OpenXML library called DocumentFormat.OpenXML.
At first it looked good but it had some major performance issued while using the object oriented style. I switched over to the OpenXMLWriter (SAX) but this introduced another class of problems like corrupted files. The Documentation is a pile of shit and a while I gave up and reimplemented my export with NPOI.
To have it a little simpler i wrote some helper functions to do the cell and row injection. The result is as follows.
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
namespace MyStuff
{
public class XLSXExport
{
private Int32 SheetRowIndex = 0;
private Int32 SheetCellIndex = 0;
private ISheet Sheet { get; set; }
private IRow SheetRow { get; set; }
private IWorkbook WorkBook { get; set; }
private ICreationHelper CreationHelper { get; set; }
public CultureInfo ExportCulture { get; set; }
public XLSXExport()
{
Data = new List<ExportCurveData>();
ExportCulture = CultureInfo.InvariantCulture;
WorkBook = new XSSFWorkbook();
Sheet = WorkBook.CreateSheet("mySheet");
CreationHelper = WorkBook.GetCreationHelper();
}
/// <summary>
/// Writes and reads workbook to get a byte array
/// </summary>
/// <returns>byte[]</returns>
public byte[] getContent()
{
Int32 rand = new Random().Next();
String tempFileName = rand + DateTime.Now.Ticks.ToString("X16") + ".xlsx";
String fp = Path.Combine(Path.GetTempPath(), tempFileName);
try
{
using (FileStream FSXLSX = new FileStream(fp, FileMode.Create, FileAccess.Write))
{
// create a row
CreateRow();
// insert a cell into the last created row
CreateCell("Header 1");
// insert another cell into the last created row
CreateCell("Header 2");
// write the data to the xlsx file
WorkBook.Write(FSXLSX);
}
}
catch(Exception Ex)
{
Trace.WriteLine(Ex.StackTrace.ToString());
}
Byte[] data = File.ReadAllBytes(fp);
File.Delete(fp);
return data;
}
/// <summary>
/// Creates a new Row in the current Sheet
/// </summary>
/// <param name="Data">Object to be formatted</param>
private void CreateRow()
{
try
{
SheetRow = Sheet.CreateRow(SheetRowIndex);
// increment row number
SheetRowIndex++;
// reset cell index
SheetCellIndex = 0;
}
catch(Exception Ex)
{
Trace.WriteLine(Ex.StackTrace.ToString());
throw Ex;
}
}
/// <summary>
/// Returns a new Cell
/// </summary>
/// <param name="Data">Object to be formatted</param>
private void CreateCell(Object Data)
{
try
{
ICell Cell = SheetRow.CreateCell(SheetCellIndex);
Cell.SetCellType(GetCellType(Data));
String ValueString = String.Empty;
if(Data != null)
{
if (Data is Single)
{
Single Value;
Single.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(Value);
Cell.CellStyle = WorkBook.CreateCellStyle();
Cell.CellStyle.DataFormat = CreationHelper.CreateDataFormat().GetFormat("0.000");
}
else if (Data is Double)
{
Double Value;
Double.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(Value);
Cell.CellStyle = WorkBook.CreateCellStyle();
Cell.CellStyle.DataFormat = CreationHelper.CreateDataFormat().GetFormat("0.000");
}
else if (Data is Decimal)
{
Decimal Value;
Decimal.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(Convert.ToDouble(Value));
Cell.CellStyle = WorkBook.CreateCellStyle();
Cell.CellStyle.DataFormat = CreationHelper.CreateDataFormat().GetFormat("0.000");
}
else if (Data is Int16)
{
Int16 Value;
Int16.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(Value);
}
else if (Data is Int32)
{
Int32 Value;
Int32.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(Value);
}
else if (Data is Int64)
{
Int64 Value;
Int64.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(ValueString);
}
else if (Data is UInt16)
{
UInt16 Value;
UInt16.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(Value);
}
else if (Data is UInt32)
{
UInt32 Value;
UInt32.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(Value);
}
else if (Data is UInt64)
{
UInt64 Value;
UInt64.TryParse(Data.ToString(), out Value);
Cell.SetCellValue(Value);
}
else if (Data is DateTime)
{
ValueString = String.Format(ExportCulture, "{0:s}", (DateTime) Data);
Cell.SetCellValue(ValueString);
}
else if (Data is Boolean)
{
ValueString = String.Format(ExportCulture, "{0}", (Boolean) Data ? "1" : "0");
Cell.SetCellValue(ValueString);
}
else
{
ValueString = String.Format(ExportCulture, "{0}", Data);
Cell.SetCellValue(ValueString);
}
}
SheetCellIndex++;
}
catch (Exception Ex)
{
Trace.WriteLine(Ex.StackTrace.ToString());
throw Ex;
}
}
/// <summary>
/// Return a valid CellType for the given Object data
/// </summary>
/// <param name="Data"></param>
/// <returns>CellValues</returns>
private CellType GetCellType(Object Data)
{
if (Data is Single
|| Data is Double
|| Data is Decimal
|| Data is Int16
|| Data is Int32
|| Data is Int64
|| Data is UInt16
|| Data is UInt32
|| Data is UInt64
) {
return CellType.Numeric;
}
else if(Data is Boolean)
{
return CellType.Boolean;
}
else if (Data is String)
{
if(String.IsNullOrWhiteSpace(Data as String))
{
return CellType.Blank;
}
else
{
return CellType.String;
}
}
else
{
return CellType.Unknown;
}
}
}
}