背景介绍报表绕不开 Excel。传统方案用 Microsoft.Office.Interop需要安装 Office且进程管理复杂。MiniExcel是一个轻量级库 1MB通过直接操作 ZIP 压缩包.xlsx 本质是 ZIP实现读写无需 Office 环境支持 .NET Core / .NET Framework。本篇覆盖基本读写DataTable / List ⇄ Excel写入优化避免内存膨胀样式设置列宽、行高、背景色代码实现1. 安装与基础读写dotnetaddpackage MiniExcelusingMiniExcelLibs;// 读 Excel publicvoidReadExcel(){// 读取整个 sheetvarrowsMiniExcel.Query(report.xlsx).ToList();// 读取指定 sheetvarrows2MiniExcel.Query(report.xlsx,sheetName:Sheet2).ToList();// 读取为 DataTable便于筛选vardtMiniExcel.QueryAsDataTable(report.xlsx);foreach(DataRowrowindt.Rows){Console.WriteLine(${row[DeviceId]}-{row[Value]});}}// 写 Excel publicvoidWriteSimpleExcel(){vardevicesnew[]{new{DeviceIdINJ001,Temperature85.5,Pressure1.2},new{DeviceIdINJ002,Temperature82.3,Pressure1.1}};// 最简单写法List 直接写MiniExcel.SaveAs(output.xlsx,devices);// 指定 sheet 名MiniExcel.SaveAs(output.xlsx,devices,sheetName:生产数据);}2. 写入优化分批写入大文件publicvoidWriteLargeFile(stringfilePath,IEnumerableReportRowrows){// MiniExcel 默认会把所有数据加载到内存// 大数据量时需要分批处理varbatchSize5000;varbatchnewListReportRow();using(varstreamFile.Create(filePath)){boolfirstBatchtrue;foreach(varrowinrows){batch.Add(row);if(batch.CountbatchSize){if(firstBatch){// 第一批创建文件 写入表头stream.Seek(0,SeekOrigin.Begin);MiniExcel.SaveAs(stream,batch,printHeader:true);firstBatchfalse;}else{// 后续批次追加到已有 sheet通过 sheetNameMiniExcel.AppendExcel(stream,batch,sheetName:Data);}batch.Clear();}}// 处理剩余数据if(batch.Count0){if(firstBatch)MiniExcel.SaveAs(stream,batch,printHeader:true);elseMiniExcel.AppendExcel(stream,batch,sheetName:Data);}}}publicclassReportRow{publicstringDeviceId{get;set;}publicDateTimeTimestamp{get;set;}publicdoubleTemperature{get;set;}publicdoublePressure{get;set;}}3. 使用模板生成报表// 报表模板template.xlsx包含// - A1: 标题已合并单元格// - A3: 列头DeviceId, Timestamp, Temperature...// - A4 以下数据区空着等我们填充publicvoidGenerateFromTemplate(){stringtemplatePathtemplate.xlsx;stringoutputPathreport_20240421.xlsx;// 1. 复制模板File.Copy(templatePath,outputPath,overwrite:true);// 2. 读取模板内容不覆盖格式vartemplateMiniExcel.QueryAsDataTable(outputPath);// 3. 准备数据vardataGetProductionData();// ListReportRow// 4. 写入数据从 A4 开始MiniExcel.SaveAsByTemplate(outputPath,new{Title2024年4月21日 生产报表,GenerateDateDateTime.Now.ToString(yyyy-MM-dd HH:mm),Datadata// 这个 key 会对应模板中的 Data 区域});}4. 样式设置publicvoidWriteWithStyle(){varrowsnewListDictionarystring,object{newDictionarystring,object{[DeviceId]INJ001,[Value]85.5},newDictionarystring,object{[DeviceId]INJ002,[Value]82.3}};// 设置列配置varcolumnsnewDictionarystring,MiniExcelColumnAttribute{[DeviceId]newMiniExcelColumnAttribute{Name设备编号,Width15},[Value]newMiniExcelColumnAttribute{Name测量值,Width12,Format0.00}};// 写入并设置列宽MiniExcel.SaveAs(styled.xlsx,rows,configurations:columns);}// 自定义样式需要底层操作publicvoidWriteWithCustomStyle(stringfilePath){varconfignewMiniExcelConfiguration{SheetNameReport};usingvarstreamFile.Create(filePath);stream.Seek(0,SeekOrigin.Begin);// MiniExcel 支持通过 .xlsx 的 shared strings 和 styles.xml// 完整样式控制建议用 ClosedXML 或 EPPlus}5. 读取时处理合并单元格publicvoidReadMergedCells(){// MiniExcel 默认会返回合并单元格的值到每一行// 如果需要识别合并区域手动解析varcellsMiniExcel.GetCells(merged.xlsx).ToList();varmergedRangescells.Where(cc.MergeCount0).Select(cnew{c.Value,StartRowc.Row,EndRowc.Rowc.MergeCount-1,StartColc.Column,EndColc.Column1// 简化默认横向合并}).ToList();foreach(varminmergedRanges){Console.WriteLine($合并区域:{m.Value}({m.StartRow}-{m.EndRow}));}}