Excel导出---NPOI和MS两种方式

Posted 好好学习V天天向上

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Excel导出---NPOI和MS两种方式相关的知识,希望对你有一定的参考价值。

NPOI方式(NPOI开源免费):

  1   /// <summary>
  2         /// 导出Excel文件
  3         /// </summary>
  4         /// <param name="sheetName"></param>
  5         /// <param name="titles">EXCEL表格表头</param>
  6         /// <param name="rowSpan">要合并的行数</param>
  7         /// <param name="cols">需要合并的左侧列</param>
  8         /// <param name="dt">数据表</param>
  9         /// <param name="path">保存路径</param>
 10         /// <param name="IsSpan">是否需要合并</param>
 11         /// <param name="IsFormula">是否需要导出公式</param>
 12         public static bool ExportExcelNPOI(string sheetName, List<Tuple<string, int, Type>> titles, int rowSpan, int cols, System.Data.DataTable dt, string path, bool IsSpan = true,bool IsFormula=false)
 13         {
 14             try
 15             {
 16                 IWorkbook wb = new XSSFWorkbook();
 17                 ISheet sheet = wb.CreateSheet(sheetName); //创建工作表
 18                 IRow row_Title = sheet.CreateRow(0); //创建列头行
 19                 row_Title.HeightInPoints = 19.5F; //设置列头行高
 20 
 21                 IDataFormat dataformat = wb.CreateDataFormat();//用于格式化单元格内容
 22 
 23                 #region 设置列头单元格样式
 24                 ICellStyle cs_Title = wb.CreateCellStyle(); //创建字符串列头样式
 25                 cs_Title.Alignment = HorizontalAlignment.Center; //水平居中
 26                 cs_Title.VerticalAlignment = VerticalAlignment.Center; //垂直居中
 27                 IFont cs_Title_Font = wb.CreateFont(); //创建字体
 28                 cs_Title_Font.IsBold = true; //字体加粗
 29                 cs_Title_Font.FontHeightInPoints = 12; //字体大小
 30                 cs_Title.SetFont(cs_Title_Font); //将字体绑定到样式
 31 
 32                 ICellStyle cs_Date_Title = wb.CreateCellStyle();
 33                 cs_Date_Title.CloneStyleFrom(cs_Title);
 34                 cs_Date_Title.DataFormat = dataformat.GetFormat("yyyy/M/d");
 35                 #endregion
 36 
 37                 #region 填充列头
 38                 ICell cell_Title;
 39                 int cnt = 0;
 40                 foreach (var title in titles)
 41                 {
 42                     cell_Title = row_Title.CreateCell(cnt); //创建单元格
 43 
 44                     if (title.Item3 == typeof(DateTime))
 45                     {
 46                         cell_Title.CellStyle = cs_Date_Title; //将样式绑定到单元格
 47                         cell_Title.SetCellValue(DateTime.Parse(title.Item1));
 48                     }
 49                     else if (title.Item3 == typeof(int))
 50                     {
 51                         cell_Title.CellStyle = cs_Title; //将样式绑定到单元格
 52                         cell_Title.SetCellValue(int.Parse(title.Item1));
 53                     }
 54                     else
 55                     {
 56                         cell_Title.CellStyle = cs_Title;
 57                         cell_Title.SetCellValue(title.Item1);
 58                     }
 59 
 60                     sheet.SetColumnWidth(cnt, title.Item2);//设置列宽
 61 
 62                     cnt++;
 63                 }
 64                 #endregion
 65 
 66                 #region 填充数据
 67                 List<int> valueTypeColNo = new List<int>();//除日期列和总计列之外其它值类型列的列号
 68                 if (dt.Columns.Contains("Inventory"))
 69                 {
 70                     valueTypeColNo.Add(dt.Columns["Inventory"].Ordinal);
 71                 }
 72 
 73                 int indexNo = 1;//序号
 74                 int dataRowNum = 0;//DataTalbe数据行行号
 75                 int excelRowNum = 0;//Excel数据行行号
 76                 #region 计算公式列名
 77                 string startCol, endCol;
 78                 string inventoryCol, demandCol, commitCol;
 79                 #endregion
 80                 foreach (DataRow row in dt.Rows)
 81                 {
 82                     excelRowNum = dataRowNum + 1;
 83 
 84                     #region 设置内容单元格样式
 85                     ICellStyle cs_Content = wb.CreateCellStyle(); //创建单元格样式
 86                     cs_Content.Alignment = HorizontalAlignment.Center; //水平居中
 87                     cs_Content.VerticalAlignment = VerticalAlignment.Center; //垂直居中
 88 
 89 
 90                     ICellStyle cs_Content_Date = wb.CreateCellStyle();
 91                     cs_Content_Date.CloneStyleFrom(cs_Content);
 92                     cs_Content_Date.DataFormat = dataformat.GetFormat("yyyy/M/d");
 93                     #endregion
 94 
 95                     IRow row_Content = sheet.CreateRow(excelRowNum); //创建数据行
 96                     row_Content.HeightInPoints = 16;
 97 
 98                     #region 设置序号
 99                     ICell cell_IndexNo = row_Content.CreateCell(0); //序号列
100                     cell_IndexNo.CellStyle = cs_Content;
101 
102                     if (dataRowNum % rowSpan == 0)
103                     {
104                         cell_IndexNo.SetCellValue(indexNo);
105                         indexNo++;
106                     }
107                     if (IsSpan && excelRowNum % rowSpan == 0)//合并单元格
108                     {
109                         sheet.AddMergedRegion(new CellRangeAddress(excelRowNum - (rowSpan - 1), excelRowNum, 0, 0));
110                     }
111                     #endregion
112 
113                     for (int j = 0; j < dt.Columns.Count; j++)
114                     {
115                         ICell cell_Conent = row_Content.CreateCell(j + 1); //创建单元格
116                         cell_Conent.CellStyle = cs_Content;
117 
118                         if (row[j] == DBNull.Value)
119                         {
120                             cell_Conent.SetCellValue(string.Empty);
121                         }
122                         else
123                         {
124                             if (row[j].GetType() == typeof(int))
125                             {
126                                 cell_Conent.SetCellValue(int.Parse(row[j].ToString()));
127                             }
128                             else if (row[j].GetType() == typeof(DateTime))
129                             {
130                                 cell_Conent.CellStyle = cs_Content_Date;
131                                 cell_Conent.SetCellValue(DateTime.Parse(row[j].ToString()));
132                             }
133                             else
134                             {
135                                 cell_Conent.SetCellValue(row[j].ToString());
136                             }
137                         }
138 
139                         if (IsSpan && excelRowNum % rowSpan == 0 && j < cols - 1)//合并单元格
140                         {
141                             sheet.AddMergedRegion(new CellRangeAddress(excelRowNum - (rowSpan - 1), excelRowNum, j + 1, j + 1));
142                         }
143 
144                         #region 导出公式
145                         if (IsFormula)
146                         {
147                             if (j == dt.Columns.Count - 1)//最后一列求和
148                             {
149                                 startCol = EXCELUtilty.GetCellIdentity(cell_Conent.ColumnIndex - (dt.Columns.Count - cols - 1), excelRowNum + 1);
150                                 endCol = EXCELUtilty.GetCellIdentity(cell_Conent.ColumnIndex - 1, excelRowNum + 1);
151                                 cell_Conent.SetCellFormula(string.Format("sum({0}:{1})", startCol, endCol));
152                             }
153 
154                             if (excelRowNum % rowSpan == 0 && j != dt.Columns.Count - 1)
155                             {
156                                 if (j == cols)//第一个日期列
157                                 {
158                                     inventoryCol = EXCELUtilty.GetCellIdentity(cell_Conent.ColumnIndex - 2, excelRowNum - rowSpan + 2);
159                                     demandCol = EXCELUtilty.GetCellIdentity(cell_Conent.ColumnIndex, excelRowNum - rowSpan + 2);
160                                     commitCol = EXCELUtilty.GetCellIdentity(cell_Conent.ColumnIndex, excelRowNum - rowSpan + 3);
161                                     cell_Conent.SetCellFormula(string.Format("{0}+{1}-{2}", inventoryCol, commitCol, demandCol));
162                                 }
163                                 else if (j > cols)
164                                 {
165                                     inventoryCol = EXCELUtilty.GetCellIdentity(cell_Conent.ColumnIndex - 1, excelRowNum + 1);
166                                     demandCol = EXCELUtilty.GetCellIdentity(cell_Conent.ColumnIndex, excelRowNum - rowSpan + 2);
167                                     commitCol = EXCELUtilty.GetCellIdentity(cell_Conent.ColumnIndex, excelRowNum - rowSpan + 3);
168                                     cell_Conent.SetCellFormula(string.Format("{0}+{1}-{2}", inventoryCol, commitCol, demandCol));
169                                 }
170 
171                             }
172 
173                         }
174                         #endregion
175                     }
176                         
177                     dataRowNum++;
178                 }
179 
180                 sheet.ForceFormulaRecalculation = true;//激活公式
181                 #endregion
182 
183                 using (FileStream file = new FileStream(path, FileMode.Create, FileAccess.Write))
184                 {
185                     wb.Write(file);
186                 }
187 
188                 return true;
189             }
190             catch
191             {
192                 return false;
193             }
194         }
View Code

 

MS方式(有版权的,微软要收费):

 1  /// <summary>
 2         /// 导出Excel文件
 3         /// </summary>
 4         /// <param name="sheetName"></param>
 5         /// <param name="titles">EXCEL表格表头</param>
 6         /// <param name="rowSpan">要合并的行数</param>
 7         /// <param name="cols">需要合并的左侧列</param>
 8         /// <param name="dt"></param>
 9         public static void ExportExcel(string sheetName, Dictionary<string, int> titles, int rowSpan, int cols, System.Data.DataTable dt, bool IsSpan = true)
10         {
11             //0.注意:  
12             // * Excel中形如Cells[x][y]的写法,前面的数字是列,后面的数字是行!  
13             // * Excel中的行、列都是从1开始的,而不是0  
14             //制作一个新的Excel文档实例  
15             EXCEL.Application xlsApp = new EXCEL.Application();
16             xlsApp.DisplayAlerts = false;
17             xlsApp.Workbooks.Add(true);
18             //设置Excel分页卡标题  
19             xlsApp.ActiveSheet.Name = sheetName;
20 
21             EXCEL.Range range;
22 
23             //填写各列的标题行
24             int colNum = 1;//列号
25             int rowNum = 1;//行号
26 
27             int cnt = 0;
28             foreach (var title in titles)
29             {
30                 xlsApp.Cells[colNum + cnt][rowNum] = title.Key;
31                 xlsApp.Cells[colNum + cnt][rowNum].ColumnWidth = title.Value;
32                 cnt++;
33             }
34 
35             xlsApp.Rows[rowNum].Font.Name = "宋体";
36             xlsApp.Rows[rowNum].Font.Size = 13;//设置字号  
37             xlsApp.Rows[rowNum].Font.Bold = true;//粗体  
38             xlsApp.Rows[rowNum].HorizontalAlignment = Microsoft.Office.Interop.Excel.XlVAlign.xlVAlignCenter;//居中
39 
40             //填充数据
41             int rcnt = 0;
42             int indexNo = 1;//序号列
43             int row;//EXCEL行号
44             int col;//EXCEL列号
45            
46             for (int i = 0; i < dt.Rows.Count; i++)
47             {
48                 row = i + 2;
49 
50                 #region 设置序号
51                 if (rcnt % rowSpan == 0)
52                 {
53                     xlsApp.Cells[1][row] = indexNo;
54                     indexNo++;
55                 }
56                 if (IsSpan && (row - 1) % rowSpan == 0)
57                 {
58                     range = xlsApp.ActiveSheet.Range[xlsApp.ActiveSheet.Cells[row - (rowSpan-1), 1], xlsApp.ActiveSheet.Cells[row, 1]];
59                     range.Merge(0);
60                     xlsApp.ActiveSheet.Cells[row - (rowSpan - 1), 1] = indexNo - 1;
61                 }
62                 #endregion
63 
64                 for (int j = 0; j < dt.Columns.Count; j++)
65                 {
66                     col = j + 2;
67                     xlsApp.Cells[col][row] = dt.Rows[i][j];//填充值
68 
69                     if (IsSpan && (row - 1) % rowSpan == 0 && col <= cols)
70                     {
71                         range = xlsApp.ActiveSheet.Range[xlsApp.ActiveSheet.Cells[row - (rowSpan - 1), col], xlsApp.ActiveSheet.Cells[row, col]];
72                         range.Merge(0);
73                         xlsApp.ActiveSheet.Cells[row - (rowSpan - 1), col] = dt.Rows[i - (rowSpan - 1)][j];
74                     }
75                 }
76 
77                 rcnt++;
78             }
79 
80             //打开制作完毕的表格  
81             xlsApp.Visible = true;
82         }
View Code

 

这里介绍一个坑,如果通过AJAX导出EXCEL,浏览器无法直接下载文件。我的做法是先把文件存到服务器上,向前端ajax方法返回服务器路径。

 function openExport() {
            var Id = $("#Id").val();
            $.ajax({
                type: \'POST\',
                url: "/XXX/ExportExcel?Id=" + Id,
                success: function (res) {
                    if (res.type === \'E\') {
                        $.hqmsg.showMsg({ msgtype: \'E\', content: "导出失败" });
                    } else if (res.type === \'S\') {
                        $.hqmsg.showMsg({ msgtype: \'S\', content: "导出成功" });
                        var link = $(\'<a href="\' + res.message + \'" target="_blank"></a>\');
                        link.get(0).click();
                    }
                }
            });
        }

 

辅助类代码:

  1 class EXCELUtilty
  2     {
  3         public static ISheet GetExcelSheet(string path,int sheetIndex)
  4         {
  5             IWorkbook book;
  6             try
  7             {
  8                 using (var file = new FileStream(path, FileMode.Open, FileAccess.Read))
  9                 {
 10                     book = WorkbookFactory.Create(file);
 11                     return book.GetSheetAt(sheetIndex);
 12                 }
 13             }
 14             catch
 15             {
 16                 return null;
 17             }
 18         }
 19 
 20         /// <summary>
 21         /// 读Excel单元格的数据
 22         /// </summary>
 23         /// <param name="cell">Excel单元格</param>
 24         /// <param name="type">列数据类型</param>
 25         /// <returns>object 单元格数据</returns>
 26         public static dynamic GetCellData(ICell cell, Type type)
 27         {
 28             var cellValue = GetCellValue(cell);
 29             if (cellValue == null)
 30             {
 31                 return DBNull.Value;
 32             }
 33 
 34             if (type.Name == "Int32")
 35             {
 36                 int intobj = 0;
 37                 if (int.TryParse(cellValue, out intobj))
 38                 {
 39                     return intobj;
 40                 }
 41                 else
 42                 {
 43                     return DBNull.Value;
 44                 }
 45             }
 46             else if (type.Name == "Decimal")
 47             {
 48                 decimal decobj = 0.0m;
 49                 if (decimal.TryParse(cellValue, out decobj))
 50                 {
 51                     return decobj;
 52          

以上是关于Excel导出---NPOI和MS两种方式的主要内容,如果未能解决你的问题,请参考以下文章

Winform中通过NPOI导出Excel的三种方式(HSSFWorkbook,XSSFWorkbook,SXSSFWorkbook)附代码下载

.net 用NPOI 方式导出EXCEL ,如果自动生成相应的统计图表

npoi导入导出excel (泛型)

.Net Core+NPOI快速导入导出Excel

Office Com组件根据模板导出Excel

NPOI导出Excel