- A+
所属分类:.NET技术
选择第三方库
- Epplus : 5.0后出现授权问题 out
- Magicodes.IE : 基于Epplush 4.x , IExporterHeaderFilter 这个的性能很渣,而且动态调整order会出现顺序错乱 out
- NPOI : 个人不是太喜欢
- ClosedXML : 基于 Document.OpenXML ,性能不错但是需要自己封装一些业务功能 i like this
简单导出功能
//导出 protected override void Action() { //创建workbook var wb = new XLWorkbook(XLEventTracking.Disabled); wb.Worksheets.Add("test", Datas); wb.SaveAs($"{Guid.NewGuid()}.xlsx"); } internal static class ClosedXMLExtension { //添加IXLWorksheet扩展 你也可以基于函数封装 public static IXLWorksheet Add<T>(this IXLWorksheets wss, string sheetName, IEnumerable<T> datas) { var ws = wss.Add(sheetName); var props = typeof(T).GetProperties(); int row = 1, col = 1; foreach (var data in datas) { foreach (var prop in props) { ws.Cell(row, col).Value = prop.GetValue(data); col++; } col = 1; row++; } return ws; } }
进一步封装
说明
- 整体使用反射获取值向cell中填充
- header可以动态控制,但是控制流实现的比较简单
- 使用model字段的小写与动态header进行匹配
public static class ClosedXMLExtension { /// <summary> /// 向单个sheet填充数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="wss">IXLWorksheets</param> /// <param name="sheetName">sheet 名称(需要唯一)</param> /// <param name="dataSource">数据源</param> /// <returns></returns> public static IXLWorksheet Add<T>(this IXLWorksheets wss, string sheetName, IEnumerable<T> dataSource, Dictionary<string, DynamicHeader> headers = null) { if (dataSource == null) throw new ArgumentNullException(nameof(dataSource), "datasource cant be null"); if (string.IsNullOrEmpty(sheetName)) throw new ArgumentNullException(nameof(dataSource), "sheet's name cant be null"); //创建sheet var ws = wss.Add(sheetName); //如果header中没有数据,直接返回 if (headers != null && !headers.Any()) return ws; var props = typeof(T).GetProperties(); headers = ChangeDynamicHeadersOrder(headers); AddHeader(ws, headers == null ? props.Select(x => x.Name) : headers.Select(x => x.Value.DisplayName)); int row = 2, col = 1; foreach (var data in dataSource) { foreach (var prop in props) { if (headers == null) { ws.Cell(row, col).Value = prop.GetValue(data); col++; } else if (headers.TryGetValue(prop.Name.ToLower(), out var dynamicHeader)) ws.Cell(row, dynamicHeader.Index).Value = prop.GetValue(data); } col = 1; row++; } return ws; } /// <summary> /// 添加表格头 /// </summary> /// <param name="ws"></param> /// <param name="headerNames"></param> private static void AddHeader(IXLWorksheet ws, IEnumerable<string> headerNames) { int row = 1, col = 1; foreach (var name in headerNames) { var cell = ws.Cell(row, col); cell.Value = name; cell.Style.Font.Bold = true; cell.Style.Fill.SetBackgroundColor(XLColor.LightBlue); col++; } } /// <summary> /// 修改header的顺序防止数据重叠 /// </summary> /// <param name="headers"></param> /// <returns></returns> private static Dictionary<string, DynamicHeader> ChangeDynamicHeadersOrder(Dictionary<string, DynamicHeader> headers) { if (headers == null) return null; var temp = headers .OrderBy(x => x.Value.Index) .Select((x, index) => new KeyValuePair<string, DynamicHeader>( x.Key.ToLower(), new DynamicHeader() { Index = index + 1, DisplayName = x.Value.DisplayName } )); return temp.ToDictionary(x => x.Key, x => x.Value); } } public class DynamicHeader { /// <summary> /// 序号 /// </summary> public int Index { get; set; } /// <summary> /// Header显示名称 /// </summary> public string DisplayName { get; set; } }