zoukankan      html  css  js  c++  java
  • .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多少感觉有点麻烦。
     
  • 相关阅读:
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
    java io系列20之 PipedReader和PipedWriter
    java io系列19之 CharArrayWriter(字符数组输出流)
    java io系列18之 CharArrayReader(字符数组输入流)
    java io系列17之 System.out.println("hello world")原理
    java io系列16之 PrintStream(打印输出流)详解
    java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
    java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
  • 原文地址:https://www.cnblogs.com/activities/p/2762978.html
Copyright © 2011-2022 走看看