zoukankan      html  css  js  c++  java
  • .NET使用NPOI组件将数据导出Excel(转)

    Excel导入及导出问题产生:


      从接触.net到现在一直在维护一个DataTable导出到Excel的类,时不时还会维护一个导入类。以下是时不时就会出现的问题:

    导出问题:

      如果是asp.net,你得在服务器端装Office,几百M呢,还得及时更新它,以防漏洞,还得设定权限允许ASP.net访问COM+,听说如果导出过程中出问题可能导致服务器宕机。

      Excel会把只包含数字的列进行类型转换,本来是文本型的,它非要把你转成数值型的,像身份证后三位变成000,编号000123会变成123,够智能吧,够郁闷吧。不过这些都还是可以变通解决的,在他们前边加上一个字母,让他们不只包含数字。

      导出时,如果你的字段内容以"-"或"="开头,Excel好像把它当成了公式什么的,接下来就出错,提示:类似,保存到Sheet1的问题

    导入问题:

      Excel会根据你的 Excel文件前8行分析数据类型,如果正好你前8行某一列只是数字,那它会认为你这一列就是数值型的,然后,身份证,手机,编号都转吧变成类似这样的1.42702E+17格式,日期列变成 包含日期和数字的,乱的很,可以通过改注册表让Excel分析整个表,但如果整列都是数字,那这个问题还是解决不了。


      以上问题,一般人初次做时肯定得上网查查吧,一个问题接着另一个问题,查到你郁郁而死,还有很多问题没解决,最终感觉已经解决的不错了,但还不能保证某一天还会出个什么问题。

    使用第三方开源组件导入及导出Excel的解决方案:


      偶然间发现了NPOI与MyXls,相见恨晚,害的我在Excel上浪费了那么多时间,他们俩的好处是:就是.net的自定义类库,可以直接对Excel进行读或写,而不依赖Office 的 Excel,这不管对于ASP.net或Winform都非常有利,不用担心Excel进程的释放问题,服务器安全,设置,导出,导入“Excel智能识别”,公式日期等问题,可以说以前的Excel问题,全都不用管了,它们可以很好的帮你解决,NPOI || MyXls == 研究几年Excel。

      NPOI开源地址:http://npoi.codeplex.com/

      MyXls开源地址:http://sourceforge.net/projects/myxls/

    下面来两个简单入门例子:
    MyXls 快速入门例子:

    1 /// <summary>
    2 /// MyXls简单Demo,快速入门代码
    3 /// </summary>
    4 /// <param name="dtSource"></param>
    5 /// <param name="strFileName"></param>
    6 /// <remarks>MyXls认为Excel的第一个单元格是:(1,1)</remarks>
    7 /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
    8 public static void ExportEasy(DataTable dtSource, string strFileName)
    9 {
    10 XlsDocument xls = new XlsDocument();
    11 Worksheet sheet = xls.Workbook.Worksheets.Add("Sheet1");
    12
    13 //填充表头
    14 foreach (DataColumn col in dtSource.Columns)
    15 {
    16 sheet.Cells.Add(1, col.Ordinal + 1, col.ColumnName);
    17 }
    18
    19 //填充内容
    20 for (int i = 0; i < dtSource.Rows.Count; i++)
    21 {
    22 for (int j = 0; j < dtSource.Columns.Count; j++)
    23 {
    24 sheet.Cells.Add(i + 2, j + 1, dtSource.Rows[i][j].ToString());
    25 }
    26 }
    27
    28 //保存
    29 xls.FileName = strFileName;
    30 xls.Save();
    31 }

    NPOI 快速入门例子:

    1 /// <summary>
    2 /// NPOI简单Demo,快速入门代码
    3 /// </summary>
    4 /// <param name="dtSource"></param>
    5 /// <param name="strFileName"></param>
    6 /// <remarks>NPOI认为Excel的第一个单元格是:(0,0)</remarks>
    7 /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
    8 public static void ExportEasy(DataTable dtSource, string strFileName)
    9 {
    10 HSSFWorkbook workbook = new HSSFWorkbook();
    11 HSSFSheet sheet = workbook.CreateSheet();
    12
    13 //填充表头
    14 HSSFRow dataRow = sheet.CreateRow(0);
    15 foreach (DataColumn column in dtSource.Columns)
    16 {
    17 dataRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
    18 }
    19
    20
    21 //填充内容
    22 for (int i = 0; i < dtSource.Rows.Count; i++)
    23 {
    24 dataRow = sheet.CreateRow(i + 1);
    25 for (int j = 0; j < dtSource.Columns.Count; j++)
    26 {
    27 dataRow.CreateCell(j).SetCellValue(dtSource.Rows[i][j].ToString());
    28 }
    29 }
    30
    31
    32 //保存
    33 using (MemoryStream ms = new MemoryStream())
    34 {
    35 using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
    36 {
    37 workbook.Write(fs);
    38 }
    39 }
    40 workbook.Dispose();
    41 }

    接下来是柳永法(yongfa365)'Blog封装的可以用在实际项目中的类,实现的功能有(仅NPOI):

    1. 支持web及winform从DataTable导出到Excel。
    2. 生成速度很快。
    3. 准确判断数据类型,不会出现身份证转数值等上面提到的一系列问题。
    4. 如果单页条数大于65535时会新建工作表。
    5. 列宽自适应。
    6. 支持读取Excel。
    7. 调用方便,只一调用一个静态类就OK了。
    8. 因为测试期间发现MyXls导出速度要比NPOI慢3倍,而NPOI既能满足我们的导出需求,又能很好的满足我们的导入需求,所以只针对NPOI进行全方位功能实现及优化。

    MyXls导出相关类:

    1 using System;
    2 using System.Collections.Generic;
    3 using System.Linq;
    4 using System.Text;
    5 using org.in2bits.MyXls;
    6 using org.in2bits.MyXls.ByteUtil;
    7 using System.Data;
    8
    9 class ExcelHelper
    10 {
    11 public static void Export(DataTable dtSource, string strHeaderText, string strFileName)
    12 {
    13 XlsDocument xls = new XlsDocument();
    14 xls.FileName = DateTime.Now.ToString("yyyyMMddHHmmssffff", System.Globalization.DateTimeFormatInfo.InvariantInfo);
    15 xls.SummaryInformation.Author = "yongfa365"; //填加xls文件作者信息
    16 xls.SummaryInformation.NameOfCreatingApplication = "liu yongfa"; //填加xls文件创建程序信息
    17 xls.SummaryInformation.LastSavedBy = "LastSavedBy"; //填加xls文件最后保存者信息
    18 xls.SummaryInformation.Comments = "Comments"; //填加xls文件作者信息
    19 xls.SummaryInformation.Title = "title"; //填加xls文件标题信息
    20 xls.SummaryInformation.Subject = "Subject";//填加文件主题信息
    21 xls.DocumentSummaryInformation.Company = "company";//填加文件公司信息
    22
    23
    24 Worksheet sheet = xls.Workbook.Worksheets.Add("Sheet1");//状态栏标题名称
    25 Cells cells = sheet.Cells;
    26
    27 foreach (DataColumn col in dtSource.Columns)
    28 {
    29 Cell cell = cells.Add(1, col.Ordinal + 1, col.ColumnName);
    30 cell.Font.FontFamily = FontFamilies.Roman; //字体
    31 cell.Font.Bold = true; //字体为粗体
    32
    33 }
    34 #region 填充内容
    35 XF dateStyle = xls.NewXF();
    36 dateStyle.Format = "yyyy-mm-dd";
    37
    38 for (int i = 0; i < dtSource.Rows.Count; i++)
    39 {
    40 for (int j = 0; j < dtSource.Columns.Count; j++)
    41 {
    42
    43 int rowIndex = i + 2;
    44 int colIndex = j + 1;
    45 string drValue = dtSource.Rows[i][j].ToString();
    46
    47 switch (dtSource.Rows[i][j].GetType().ToString())
    48 {
    49 case "System.String"://字符串类型
    50 cells.Add(rowIndex, colIndex, drValue);
    51 break;
    52 case "System.DateTime"://日期类型
    53 DateTime dateV;
    54 DateTime.TryParse(drValue, out dateV);
    55 cells.Add(rowIndex, colIndex, dateV, dateStyle);
    56 break;
    57 case "System.Boolean"://布尔型
    58 bool boolV = false;
    59 bool.TryParse(drValue, out boolV);
    60 cells.Add(rowIndex, colIndex, boolV);
    61 break;
    62 case "System.Int16"://整型
    63 case "System.Int32":
    64 case "System.Int64":
    65 case "System.Byte":
    66 int intV = 0;
    67 int.TryParse(drValue, out intV);
    68 cells.Add(rowIndex, colIndex, intV);
    69 break;
    70 case "System.Decimal"://浮点型
    71 case "System.Double":
    72 double doubV = 0;
    73 double.TryParse(drValue, out doubV);
    74 cells.Add(rowIndex, colIndex, doubV);
    75 break;
    76 case "System.DBNull"://空值处理
    77 cells.Add(rowIndex, colIndex, null);
    78 break;
    79 default:
    80 cells.Add(rowIndex, colIndex, null);
    81 break;
    82 }
    83 }
    84 }
    85
    86 #endregion
    87
    88 xls.FileName = strFileName;
    89 xls.Save();
    90 }
    91 }
    92

    NPOI导入导出相关类:

    1 using System;
    2 using System.Collections.Generic;
    3 using System.Data;
    4 using System.IO;
    5 using System.Text;
    6 using System.Web;
    7 using NPOI;
    8 using NPOI.HPSF;
    9 using NPOI.HSSF;
    10 using NPOI.HSSF.UserModel;
    11 using NPOI.HSSF.Util;
    12 using NPOI.POIFS;
    13 using NPOI.Util;
    14
    15
    16 public class ExcelHelper
    17 {
    18 /// <summary>
    19 /// DataTable导出到Excel文件
    20 /// </summary>
    21 /// <param name="dtSource">源DataTable</param>
    22 /// <param name="strHeaderText">表头文本</param>
    23 /// <param name="strFileName">保存位置</param>
    24 /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
    25 public static void Export(DataTable dtSource, string strHeaderText, string strFileName)
    26 {
    27 using (MemoryStream ms = Export(dtSource, strHeaderText))
    28 {
    29 using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
    30 {
    31 byte[] data = ms.ToArray();
    32 fs.Write(data, 0, data.Length);
    33 fs.Flush();
    34 }
    35 }
    36 }
    37
    38 /// <summary>
    39 /// DataTable导出到Excel的MemoryStream
    40 /// </summary>
    41 /// <param name="dtSource">源DataTable</param>
    42 /// <param name="strHeaderText">表头文本</param>
    43 /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
    44 public static MemoryStream Export(DataTable dtSource, string strHeaderText)
    45 {
    46 HSSFWorkbook workbook = new HSSFWorkbook();
    47 HSSFSheet sheet = workbook.CreateSheet();
    48
    49 #region 右击文件 属性信息
    50 {
    51 DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
    52 dsi.Company = "http://www.yongfa365.com/";
    53 workbook.DocumentSummaryInformation = dsi;
    54
    55 SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
    56 si.Author = "柳永法"; //填加xls文件作者信息
    57 si.ApplicationName = "NPOI测试程序"; //填加xls文件创建程序信息
    58 si.LastAuthor = "柳永法2"; //填加xls文件最后保存者信息
    59 si.Comments = "说明信息"; //填加xls文件作者信息
    60 si.Title = "NPOI测试"; //填加xls文件标题信息
    61 si.Subject = "NPOI测试Demo";//填加文件主题信息
    62 si.CreateDateTime = DateTime.Now;
    63 workbook.SummaryInformation = si;
    64 }
    65 #endregion
    66
    67 HSSFCellStyle dateStyle = workbook.CreateCellStyle();
    68 HSSFDataFormat format = workbook.CreateDataFormat();
    69 dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");
    70
    71 //取得列宽
    72 int[] arrColWidth = new int[dtSource.Columns.Count];
    73 foreach (DataColumn item in dtSource.Columns)
    74 {
    75 arrColWidth[item.Ordinal] = Encoding.GetEncoding(936).GetBytes(item.ColumnName.ToString()).Length;
    76 }
    77 for (int i = 0; i < dtSource.Rows.Count; i++)
    78 {
    79 for (int j = 0; j < dtSource.Columns.Count; j++)
    80 {
    81 int intTemp = Encoding.GetEncoding(936).GetBytes(dtSource.Rows[i][j].ToString()).Length;
    82 if (intTemp > arrColWidth[j])
    83 {
    84 arrColWidth[j] = intTemp;
    85 }
    86 }
    87 }
    88
    89
    90
    91 int rowIndex = 0;
    92
    93 foreach (DataRow row in dtSource.Rows)
    94 {
    95 #region 新建表,填充表头,填充列头,样式
    96 if (rowIndex == 65535 || rowIndex == 0)
    97 {
    98 if (rowIndex != 0)
    99 {
    100 sheet = workbook.CreateSheet();
    101 }
    102
    103 #region 表头及样式
    104 {
    105 HSSFRow headerRow = sheet.CreateRow(0);
    106 headerRow.HeightInPoints = 25;
    107 headerRow.CreateCell(0).SetCellValue(strHeaderText);
    108
    109 HSSFCellStyle headStyle = workbook.CreateCellStyle();
    110 headStyle.Alignment = CellHorizontalAlignment.CENTER;
    111 HSSFFont font = workbook.CreateFont();
    112 font.FontHeightInPoints = 20;
    113 font.Boldweight = 700;
    114 headStyle.SetFont(font);
    115
    116 headerRow.GetCell(0).CellStyle = headStyle;
    117
    118 sheet.AddMergedRegion(new Region(0, 0, 0, dtSource.Columns.Count - 1));
    119 headerRow.Dispose();
    120 }
    121 #endregion
    122
    123
    124 #region 列头及样式
    125 {
    126 HSSFRow headerRow = sheet.CreateRow(1);
    127
    128
    129 HSSFCellStyle headStyle = workbook.CreateCellStyle();
    130 headStyle.Alignment = CellHorizontalAlignment.CENTER;
    131 HSSFFont font = workbook.CreateFont();
    132 font.FontHeightInPoints = 10;
    133 font.Boldweight = 700;
    134 headStyle.SetFont(font);
    135
    136
    137 foreach (DataColumn column in dtSource.Columns)
    138 {
    139 headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
    140 headerRow.GetCell(column.Ordinal).CellStyle = headStyle;
    141
    142 //设置列宽
    143 sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);
    144
    145 }
    146 headerRow.Dispose();
    147 }
    148 #endregion
    149
    150 rowIndex = 2;
    151 }
    152 #endregion
    153
    154
    155 #region 填充内容
    156 HSSFRow dataRow = sheet.CreateRow(rowIndex);
    157 foreach (DataColumn column in dtSource.Columns)
    158 {
    159 HSSFCell newCell = dataRow.CreateCell(column.Ordinal);
    160
    161 string drValue = row[column].ToString();
    162
    163 switch (column.DataType.ToString())
    164 {
    165 case "System.String"://字符串类型
    166 newCell.SetCellValue(drValue);
    167 break;
    168 case "System.DateTime"://日期类型
    169 DateTime dateV;
    170 DateTime.TryParse(drValue, out dateV);
    171 newCell.SetCellValue(dateV);
    172
    173 newCell.CellStyle = dateStyle;//格式化显示
    174 break;
    175 case "System.Boolean"://布尔型
    176 bool boolV = false;
    177 bool.TryParse(drValue, out boolV);
    178 newCell.SetCellValue(boolV);
    179 break;
    180 case "System.Int16"://整型
    181 case "System.Int32":
    182 case "System.Int64":
    183 case "System.Byte":
    184 int intV = 0;
    185 int.TryParse(drValue, out intV);
    186 newCell.SetCellValue(intV);
    187 break;
    188 case "System.Decimal"://浮点型
    189 case "System.Double":
    190 double doubV = 0;
    191 double.TryParse(drValue, out doubV);
    192 newCell.SetCellValue(doubV);
    193 break;
    194 case "System.DBNull"://空值处理
    195 newCell.SetCellValue("");
    196 break;
    197 default:
    198 newCell.SetCellValue("");
    199 break;
    200 }
    201
    202 }
    203 #endregion
    204
    205 rowIndex++;
    206 }
    207
    208
    209 using (MemoryStream ms = new MemoryStream())
    210 {
    211 workbook.Write(ms);
    212 ms.Flush();
    213 ms.Position = 0;
    214
    215 sheet.Dispose();
    216 //workbook.Dispose();//一般只用写这一个就OK了,他会遍历并释放所有资源,但当前版本有问题所以只释放sheet
    217 return ms;
    218 }
    219
    220 }
    221
    222
    223 /// <summary>
    224 /// 用于Web导出
    225 /// </summary>
    226 /// <param name="dtSource">源DataTable</param>
    227 /// <param name="strHeaderText">表头文本</param>
    228 /// <param name="strFileName">文件名</param>
    229 /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
    230 public static void ExportByWeb(DataTable dtSource, string strHeaderText, string strFileName)
    231 {
    232
    233 HttpContext curContext = HttpContext.Current;
    234
    235 // 设置编码和附件格式
    236 curContext.Response.ContentType = "application/vnd.ms-excel";
    237 curContext.Response.ContentEncoding = Encoding.UTF8;
    238 curContext.Response.Charset = "";
    239 curContext.Response.AppendHeader("Content-Disposition",
    240 "attachment;filename=" + HttpUtility.UrlEncode(strFileName, Encoding.UTF8));
    241
    242 curContext.Response.BinaryWrite(Export(dtSource, strHeaderText).GetBuffer());
    243 curContext.Response.End();
    244
    245 }
    246
    247
    248 /// <summary>读取excel
    249 /// 默认第一行为标头
    250 /// </summary>
    251 /// <param name="strFileName">excel文档路径</param>
    252 /// <returns></returns>
    253 public static DataTable Import(string strFileName)
    254 {
    255 DataTable dt = new DataTable();
    256
    257 HSSFWorkbook hssfworkbook;
    258 using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read))
    259 {
    260 hssfworkbook = new HSSFWorkbook(file);
    261 }
    262 HSSFSheet sheet = hssfworkbook.GetSheetAt(0);
    263 System.Collections.IEnumerator rows = sheet.GetRowEnumerator();
    264
    265 HSSFRow headerRow = sheet.GetRow(0);
    266 int cellCount = headerRow.LastCellNum;
    267
    268 for (int j = 0; j < cellCount; j++)
    269 {
    270 HSSFCell cell = headerRow.GetCell(j);
    271 dt.Columns.Add(cell.ToString());
    272 }
    273
    274 for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
    275 {
    276 HSSFRow row = sheet.GetRow(i);
    277 DataRow dataRow = dt.NewRow();
    278
    279 for (int j = row.FirstCellNum; j < cellCount; j++)
    280 {
    281 if (row.GetCell(j) != null)
    282 dataRow[j] = row.GetCell(j).ToString();
    283 }
    284
    285 dt.Rows.Add(dataRow);
    286 }
    287 return dt;
    288 }
    289
    290 }

    以上相关源码及测试用例下载地址:


    参考地址:


    NPOI导出Excel表功能实现(多个工作簿):http://www.cnblogs.com/zhengjuzhuan/archive/2010/02/01/1661103.html
    在 Server 端存取 Excel 檔案的利器:NPOI Library:http://msdn.microsoft.com/zh-tw/ee818993.aspx

    总结:


      通过以上分析,我们不难发现,用NPOI或MyXls代替是Excel是很明智的,在发文前,我看到NPOI及MyXls仍然在活跃的更新中。在使用过程中发现这两个组件极相似,以前看过文章说他们使用的内核是一样的。还有NPOI是国人开发的,且有相关中文文档,在很多地方有相关引用,下载量也很大。并且它支持Excel,看到MyXls相关问题基本上没人回答,所以推荐使用NPOI。MyXls可以直接Cell.Font.Bold操作,而NPOI得使用CellType多少感觉有点麻烦。
  • 相关阅读:
    MySQL学习笔记
    Git常用命令
    MacBook Pro m1安装swoole PHP版本7.4
    斐波那契数列实现的2种方法
    归纳一些比较好用的函数
    阶乘的实现
    冒泡排序
    PHP上传图片
    PHPStorm常用快捷键
    DataTables的使用
  • 原文地址:https://www.cnblogs.com/dwfbenben/p/2285409.html
Copyright © 2011-2022 走看看