I'm using SAX approach to write .xlsx files directly with DataReader (no in-memory) and this works great. But I want columns in Excel file to be autofited too.
Using SAX approach means writing .xlsx files directly with OpenXmlWriter, unfortunally in one direction only (down the xml tree). Columns - because of xml order - must be written before actual data, meaning I cannot calculate their widths since DataReader isn't opened yet.
In past I allready implemented autofit by executing DataReader twice - first for searching longest strings to calculate column widths and then for writting actual data to .xlsx file. This is time consuming when writing large files, so I'm not happy with it.
Only option I see is to edit .xlsx file, but I can't find any SAX approach.
I managed to do autofit by using this method below, but It's a huge memory comsumption (2GB of memory for 300Mb file, approx. 1 mio rows) when Linq gets involved:
private void Autofit(string _filename)
{
using (SpreadsheetDocument Excel = SpreadsheetDocument.Open(_filename, true))
{
foreach (var wp in Excel.WorkbookPart.WorksheetParts)
{
//This line drains 2GB memory, tested on 1 mio rows for .xlsx file
var sd = wp.Worksheet.Descendants<SheetData>().First();
var cs = new Columns();
uint Col_index = 1;
//MaxText is List<string>, containing longest strings of each column
foreach (var longest_string in MaxText)
{
//CalculateWidth is a method for calculating column width
double cell_width = CalculateWidth(new System.Drawing.Font("Arial", 10), longest_string) + 1.5;
Column c = new Column { Min = Col_index, Max = Col_index, Width = cell_width, CustomWidth = true };
cs.Append(c);
Col_index++;
}
wp.Worksheet.InsertAfter(cs, sd);
}
}
}
Is there anything else I can try with OpenXml? Or maybe xlst transformation, XStreamingElement ? Or could I fix upper Linq method to not consume such memory? Any examples or links would be highly appreciated.