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; } } } }