• .net 使用NPOI或MyXls把DataTable导出到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(000, 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多少感觉有点麻烦。
     
  • 相关阅读:
    获取代理服务器ip列表的方法
    司机奖励新政策:失去的奖励还能再回来!
    成都Uber优步司机奖励政策(2月24日)
    北京Uber优步司机奖励政策(2月24日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(2月24日)
    成都Uber优步司机奖励政策(2月23日)
    北京Uber优步司机奖励政策(2月23日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(2月23日)
    Android Studio 模拟器启动问题——黑屏 死机 解决方法
    MYSQL使用mysqldump导出某个表的部分数据
  • 原文地址:https://www.cnblogs.com/OnlyDreams/p/2501860.html
Copyright © 2020-2023  润新知