So, i’m using NPOI to generate an XLSX file, but i note that it’s very slow with so mutch data. I’ve created a workaround using CSV, but it’s not good.
I learning about XLSX, and i can ‘understand struct’ xlsx file, is many XML to build a XLSX.
I try build xlsx on thats way:
public static FileResult DownloadXlsxFile_StringBuilder(this ControllerBase controller, object data,
string fileName = "file.xlsx")
{
// um arquivo XLSX nada mais é que um XLM compactado e zipado.
if (data is IEnumerable<object> dataList)
{
var sheetXml = new StringBuilder();
sheetXml.Append("""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<sheetData>
""");
// draw header
PropertyInfo[] props = dataList.First().GetType().GetProperties();
sheetXml.Append("<row>");
for (int i = 0; i < props.Length; i++)
{
sheetXml.Append($"""<c r="{(char)('A' + i)}1" t="inlineStr"><is><t>{props[i].Name}</t></is></c>""");
}
sheetXml.Append("</row>");
// draw rows
int indexRow = 1;
foreach (var dataItem in dataList)
{
IEnumerable<object> values =
props.Select(x => dataItem.GetType().GetProperty(x.Name)?.GetValue(dataItem, null));
sheetXml.Append("<row>");
int indexCol = 0;
foreach (var value in values)
{
sheetXml.Append(
$"""<c r="{(char)('A' + indexCol)}{indexRow + 1}" t="inlineStr"><is><t>{value}</t></is></c>""");
indexCol++;
}
sheetXml.Append("</row>");
indexRow++;
}
sheetXml.Append("</sheetData></worksheet>");
Console.WriteLine(sheetXml.ToString());
// draw content to Xlsx
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
// Add xl/worksheets/sheet1.xml
var sheetXmlEntry = archive.CreateEntry("xl/worksheets/sheet1.xml");
using (var stream = sheetXmlEntry.Open())
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.Write(sheetXml.ToString());
}
// Add xl/_rels/workbook.xml.rels
var workbookRelsXml = archive.CreateEntry("xl/_rels/workbook.xml.rels");
using (var stream = workbookRelsXml.Open())
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.Write(@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<Relationships xmlns=""http://schemas.openxmlformats.org/package/2006/relationships"">
<Relationship Id=""rId1"" Type=""http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"" Target=""worksheets/sheet1.xml""/>
</Relationships>");
}
// Add xl/workbook.xml
var workbookXml = archive.CreateEntry("xl/workbook.xml");
using (var stream = workbookXml.Open())
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.Write(@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<workbook xmlns=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
<sheets>
<sheet name=""Sheet1"" sheetId=""1"" r:id=""rId1""/>
</sheets>
</workbook>");
}
// Add _rels/.rels
var relsXml = archive.CreateEntry("_rels/.rels");
using (var stream = relsXml.Open())
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.Write(@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<Relationships xmlns=""http://schemas.openxmlformats.org/package/2006/relationships"">
<Relationship Id=""rId1"" Type=""http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"" Target=""xl/workbook.xml""/>
</Relationships>");
}
// Add [Content_Types].xml
var contentTypesXml = archive.CreateEntry("[Content_Types].xml");
using (var stream = contentTypesXml.Open())
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.Write(@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<Types xmlns=""http://schemas.openxmlformats.org/package/2006/content-types"">
<Default Extension=""rels"" ContentType=""application/vnd.openxmlformats-package.relationships+xml""/>
<Default Extension=""xml"" ContentType=""application/xml""/>
<Override PartName=""/xl/workbook.xml"" ContentType=""application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml""/>
<Override PartName=""/xl/worksheets/sheet1.xml"" ContentType=""application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml""/>
</Types>");
}
}
memoryStream.Position = 0;
return controller.File(memoryStream.ToArray(),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
}
}
throw new Exception("cannot convert data to IEnumerable<T> in DownloadXlsxFile");
}
When i try to open .xlsx file with LibreOfficeCalc, i have: General Error, General Error Input/Output