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/
NPOI中文文档:http://www.cnblogs.com/tonyqus/archive/2009/04/12/1434209.html
MyXls开源地址:http://sourceforge.net/projects/myxls/
下面来两个简单入门例子:
MyXls 快速入门例子:
- /// <summary>
- /// MyXls简单Demo,快速入门代码
- /// </summary>
- /// <param name="dtSource"></param>
- /// <param name="strFileName"></param>
- /// <remarks>MyXls认为Excel的第一个单元格是:(1,1)</remarks>
- /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
- public static void ExportEasy(DataTable dtSource, string strFileName)
- {
- XlsDocument xls = new XlsDocument();
- Worksheet sheet = xls.Workbook.Worksheets.Add("Sheet1");
- //填充表头
- foreach (DataColumn col in dtSource.Columns)
- {
- sheet.Cells.Add(1, col.Ordinal + 1, col.ColumnName);
- }
- //填充内容
- for (int i = 0; i < dtSource.Rows.Count; i++)
- {
- for (int j = 0; j < dtSource.Columns.Count; j++)
- {
- sheet.Cells.Add(i + 2, j + 1, dtSource.Rows[i][j].ToString());
- }
- }
- //保存
- xls.FileName = strFileName;
- xls.Save();
- }
/// <summary>/// MyXls简单Demo,快速入门代码/// </summary>/// <param name="dtSource"></param>/// <param name="strFileName"></param>/// <remarks>MyXls认为Excel的第一个单元格是:(1,1)</remarks>/// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>public static void ExportEasy(DataTable dtSource, string strFileName){ XlsDocument xls = new XlsDocument(); Worksheet sheet = xls.Workbook.Worksheets.Add("Sheet1"); //填充表头 foreach (DataColumn col in dtSource.Columns) { sheet.Cells.Add(1, col.Ordinal + 1, col.ColumnName); } //填充内容 for (int i = 0; i < dtSource.Rows.Count; i++) { for (int j = 0; j < dtSource.Columns.Count; j++) { sheet.Cells.Add(i + 2, j + 1, dtSource.Rows[i][j].ToString()); } } //保存 xls.FileName = strFileName; xls.Save();}
NPOI 快速入门例子:
- /// <summary>
- /// NPOI简单Demo,快速入门代码
- /// </summary>
- /// <param name="dtSource"></param>
- /// <param name="strFileName"></param>
- /// <remarks>NPOI认为Excel的第一个单元格是:(0,0)</remarks>
- /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
- public static void ExportEasy(DataTable dtSource, string strFileName)
- {
- HSSFWorkbook workbook = new HSSFWorkbook();
- HSSFSheet sheet = workbook.CreateSheet();
- //填充表头
- HSSFRow dataRow = sheet.CreateRow(0);
- foreach (DataColumn column in dtSource.Columns)
- {
- dataRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
- }
- //填充内容
- for (int i = 0; i < dtSource.Rows.Count; i++)
- {
- dataRow = sheet.CreateRow(i + 1);
- for (int j = 0; j < dtSource.Columns.Count; j++)
- {
- dataRow.CreateCell(j).SetCellValue(dtSource.Rows[i][j].ToString());
- }
- }
- //保存
- using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
- {
- workbook.Write(fs);
- }
- workbook.Dispose();
- }
/// <summary>/// NPOI简单Demo,快速入门代码/// </summary>/// <param name="dtSource"></param>/// <param name="strFileName"></param>/// <remarks>NPOI认为Excel的第一个单元格是:(0,0)</remarks>/// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>public static void ExportEasy(DataTable dtSource, string strFileName){ HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.CreateSheet(); //填充表头 HSSFRow dataRow = sheet.CreateRow(0); foreach (DataColumn column in dtSource.Columns) { dataRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName); } //填充内容 for (int i = 0; i < dtSource.Rows.Count; i++) { dataRow = sheet.CreateRow(i + 1); for (int j = 0; j < dtSource.Columns.Count; j++) { dataRow.CreateCell(j).SetCellValue(dtSource.Rows[i][j].ToString()); } } //保存 using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write)) { workbook.Write(fs); } workbook.Dispose();}
接下来是柳永法(yongfa365)'Blog封装的可以用在实际项目中的类,实现的功能有(仅NPOI):
- 支持web及winform从DataTable导出到Excel。
- 生成速度很快。
- 准确判断数据类型,不会出现身份证转数值等上面提到的一系列问题。
- 如果单页条数大于65535时会新建工作表。
- 列宽自适应。
- 支持读取Excel。
- 调用方便,只一调用一个静态类就OK了。
因为测试期间发现MyXls导出速度要比NPOI慢3倍,而NPOI既能满足我们的导出需求,又能很好的满足我们的导入需求,所以只针对NPOI进行全方位功能实现及优化。
MyXls导出相关类:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using org.in2bits.MyXls;
- using org.in2bits.MyXls.ByteUtil;
- using System.Data;
- class ExcelHelper
- {
- public static void Export(DataTable dtSource, string strHeaderText, string strFileName)
- {
- XlsDocument xls = new XlsDocument();
- xls.FileName = DateTime.Now.ToString("yyyyMMddHHmmssffff", System.Globalization.DateTimeFormatInfo.InvariantInfo);
- xls.SummaryInformation.Author = "yongfa365"; //填加xls文件作者信息
- xls.SummaryInformation.NameOfCreatingApplication = "liu yongfa"; //填加xls文件创建程序信息
- xls.SummaryInformation.LastSavedBy = "LastSavedBy"; //填加xls文件最后保存者信息
- xls.SummaryInformation.Comments = "Comments"; //填加xls文件作者信息
- xls.SummaryInformation.Title = "title"; //填加xls文件标题信息
- xls.SummaryInformation.Subject = "Subject";//填加文件主题信息
- xls.DocumentSummaryInformation.Company = "company";//填加文件公司信息
- Worksheet sheet = xls.Workbook.Worksheets.Add("Sheet1");//状态栏标题名称
- Cells cells = sheet.Cells;
- foreach (DataColumn col in dtSource.Columns)
- {
- Cell cell = cells.Add(1, col.Ordinal + 1, col.ColumnName);
- cell.Font.FontFamily = FontFamilies.Roman; //字体
- cell.Font.Bold = true; //字体为粗体
- }
- #region 填充内容
- XF dateStyle = xls.NewXF();
- dateStyle.Format = "yyyy-mm-dd";
- for (int i = 0; i < dtSource.Rows.Count; i++)
- {
- for (int j = 0; j < dtSource.Columns.Count; j++)
- {
- int rowIndex = i + 2;
- int colIndex = j + 1;
- string drValue = dtSource.Rows[i][j].ToString();
- switch (dtSource.Rows[i][j].GetType().ToString())
- {
- case "System.String"://字符串类型
- cells.Add(rowIndex, colIndex, drValue);
- break;
- case "System.DateTime"://日期类型
- DateTime dateV;
- DateTime.TryParse(drValue, out dateV);
- cells.Add(rowIndex, colIndex, dateV, dateStyle);
- break;
- case "System.Boolean"://布尔型
- bool boolV = false;
- bool.TryParse(drValue, out boolV);
- cells.Add(rowIndex, colIndex, boolV);
- break;
- case "System.Int16"://整型
- case "System.Int32":
- case "System.Int64":
- case "System.Byte":
- int intV = 0;
- int.TryParse(drValue, out intV);
- cells.Add(rowIndex, colIndex, intV);
- break;
- case "System.Decimal"://浮点型
- case "System.Double":
- double doubV = 0;
- double.TryParse(drValue, out doubV);
- cells.Add(rowIndex, colIndex, doubV);
- break;
- case "System.DBNull"://空值处理
- cells.Add(rowIndex, colIndex, null);
- break;
- default:
- cells.Add(rowIndex, colIndex, null);
- break;
- }
- }
- }
- #endregion
- xls.FileName = strFileName;
- xls.Save();
- }
- }
using System;using System.Collections.Generic;using System.Linq;using System.Text;using org.in2bits.MyXls;using org.in2bits.MyXls.ByteUtil;using System.Data;class ExcelHelper{ public static void Export(DataTable dtSource, string strHeaderText, string strFileName) { XlsDocument xls = new XlsDocument(); xls.FileName = DateTime.Now.ToString("yyyyMMddHHmmssffff", System.Globalization.DateTimeFormatInfo.InvariantInfo); xls.SummaryInformation.Author = "yongfa365"; //填加xls文件作者信息 xls.SummaryInformation.NameOfCreatingApplication = "liu yongfa"; //填加xls文件创建程序信息 xls.SummaryInformation.LastSavedBy = "LastSavedBy"; //填加xls文件最后保存者信息 xls.SummaryInformation.Comments = "Comments"; //填加xls文件作者信息 xls.SummaryInformation.Title = "title"; //填加xls文件标题信息 xls.SummaryInformation.Subject = "Subject";//填加文件主题信息 xls.DocumentSummaryInformation.Company = "company";//填加文件公司信息 Worksheet sheet = xls.Workbook.Worksheets.Add("Sheet1");//状态栏标题名称 Cells cells = sheet.Cells; foreach (DataColumn col in dtSource.Columns) { Cell cell = cells.Add(1, col.Ordinal + 1, col.ColumnName); cell.Font.FontFamily = FontFamilies.Roman; //字体 cell.Font.Bold = true; //字体为粗体 } #region 填充内容 XF dateStyle = xls.NewXF(); dateStyle.Format = "yyyy-mm-dd"; for (int i = 0; i < dtSource.Rows.Count; i++) { for (int j = 0; j < dtSource.Columns.Count; j++) { int rowIndex = i + 2; int colIndex = j + 1; string drValue = dtSource.Rows[i][j].ToString(); switch (dtSource.Rows[i][j].GetType().ToString()) { case "System.String"://字符串类型 cells.Add(rowIndex, colIndex, drValue); break; case "System.DateTime"://日期类型 DateTime dateV; DateTime.TryParse(drValue, out dateV); cells.Add(rowIndex, colIndex, dateV, dateStyle); break; case "System.Boolean"://布尔型 bool boolV = false; bool.TryParse(drValue, out boolV); cells.Add(rowIndex, colIndex, boolV); break; case "System.Int16"://整型 case "System.Int32": case "System.Int64": case "System.Byte": int intV = 0; int.TryParse(drValue, out intV); cells.Add(rowIndex, colIndex, intV); break; case "System.Decimal"://浮点型 case "System.Double": double doubV = 0; double.TryParse(drValue, out doubV); cells.Add(rowIndex, colIndex, doubV); break; case "System.DBNull"://空值处理 cells.Add(rowIndex, colIndex, null); break; default: cells.Add(rowIndex, colIndex, null); break; } } } #endregion xls.FileName = strFileName; xls.Save(); }}
NPOI导入导出相关类:
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.IO;
- using System.Text;
- using System.Web;
- using NPOI;
- using NPOI.HPSF;
- using NPOI.HSSF;
- using NPOI.HSSF.UserModel;
- using NPOI.HSSF.Util;
- using NPOI.POIFS;
- using NPOI.Util;
- public class ExcelHelper
- {
- /// <summary>
- /// DataTable导出到Excel文件
- /// </summary>
- /// <param name="dtSource">源DataTable</param>
- /// <param name="strHeaderText">表头文本</param>
- /// <param name="strFileName">保存位置</param>
- /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
- public static void Export(DataTable dtSource, string strHeaderText, string strFileName)
- {
- using (MemoryStream ms = Export(dtSource, strHeaderText))
- {
- using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
- {
- byte[] data = ms.ToArray();
- fs.Write(data, 0, data.Length);
- fs.Flush();
- }
- }
- }
- /// <summary>
- /// DataTable导出到Excel的MemoryStream
- /// </summary>
- /// <param name="dtSource">源DataTable</param>
- /// <param name="strHeaderText">表头文本</param>
- /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
- public static MemoryStream Export(DataTable dtSource, string strHeaderText)
- {
- HSSFWorkbook workbook = new HSSFWorkbook();
- HSSFSheet sheet = workbook.CreateSheet();
- #region 右击文件 属性信息
- {
- DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
- dsi.Company = "http://www.yongfa365.com/";
- workbook.DocumentSummaryInformation = dsi;
- SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
- si.Author = "柳永法"; //填加xls文件作者信息
- si.ApplicationName = "NPOI测试程序"; //填加xls文件创建程序信息
- si.LastAuthor = "柳永法2"; //填加xls文件最后保存者信息
- si.Comments = "说明信息"; //填加xls文件作者信息
- si.Title = "NPOI测试"; //填加xls文件标题信息
- si.Subject = "NPOI测试Demo";//填加文件主题信息
- si.CreateDateTime = DateTime.Now;
- workbook.SummaryInformation = si;
- }
- #endregion
- HSSFCellStyle dateStyle = workbook.CreateCellStyle();
- HSSFDataFormat format = workbook.CreateDataFormat();
- dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");
- //取得列宽
- int[] arrColWidth = new int[dtSource.Columns.Count];
- foreach (DataColumn item in dtSource.Columns)
- {
- arrColWidth[item.Ordinal] = Encoding.GetEncoding(936).GetBytes(item.ColumnName.ToString()).Length;
- }
- for (int i = 0; i < dtSource.Rows.Count; i++)
- {
- for (int j = 0; j < dtSource.Columns.Count; j++)
- {
- int intTemp = Encoding.GetEncoding(936).GetBytes(dtSource.Rows[i][j].ToString()).Length;
- if (intTemp > arrColWidth[j])
- {
- arrColWidth[j] = intTemp;
- }
- }
- }
- int rowIndex = 0;
- foreach (DataRow row in dtSource.Rows)
- {
- #region 新建表,填充表头,填充列头,样式
- if (rowIndex == 65535 || rowIndex == 0)
- {
- if (rowIndex != 0)
- {
- sheet = workbook.CreateSheet();
- }
- #region 表头及样式
- {
- HSSFRow headerRow = sheet.CreateRow(0);
- headerRow.HeightInPoints = 25;
- headerRow.CreateCell(0).SetCellValue(strHeaderText);
- HSSFCellStyle headStyle = workbook.CreateCellStyle();
- headStyle.Alignment = CellHorizontalAlignment.CENTER;
- HSSFFont font = workbook.CreateFont();
- font.FontHeightInPoints = 20;
- font.Boldweight = 700;
- headStyle.SetFont(font);
- headerRow.GetCell(0).CellStyle = headStyle;
- sheet.AddMergedRegion(new Region(0, 0, 0, dtSource.Columns.Count - 1));
- headerRow.Dispose();
- }
- #endregion
- #region 列头及样式
- {
- HSSFRow headerRow = sheet.CreateRow(1);
- HSSFCellStyle headStyle = workbook.CreateCellStyle();
- headStyle.Alignment = CellHorizontalAlignment.CENTER;
- HSSFFont font = workbook.CreateFont();
- font.FontHeightInPoints = 10;
- font.Boldweight = 700;
- headStyle.SetFont(font);
- foreach (DataColumn column in dtSource.Columns)
- {
- headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
- headerRow.GetCell(column.Ordinal).CellStyle = headStyle;
- //设置列宽
- sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);
- }
- headerRow.Dispose();
- }
- #endregion
- rowIndex = 2;
- }
- #endregion
- #region 填充内容
- HSSFRow dataRow = sheet.CreateRow(rowIndex);
- foreach (DataColumn column in dtSource.Columns)
- {
- HSSFCell newCell = dataRow.CreateCell(column.Ordinal);
- string drValue = row[column].ToString();
- switch (column.DataType.ToString())
- {
- case "System.String"://字符串类型
- newCell.SetCellValue(drValue);
- break;
- case "System.DateTime"://日期类型
- DateTime dateV;
- DateTime.TryParse(drValue, out dateV);
- newCell.SetCellValue(dateV);
- newCell.CellStyle = dateStyle;//格式化显示
- break;
- case "System.Boolean"://布尔型
- bool boolV = false;
- bool.TryParse(drValue, out boolV);
- newCell.SetCellValue(boolV);
- break;
- case "System.Int16"://整型
- case "System.Int32":
- case "System.Int64":
- case "System.Byte":
- int intV = 0;
- int.TryParse(drValue, out intV);
- newCell.SetCellValue(intV);
- break;
- case "System.Decimal"://浮点型
- case "System.Double":
- double doubV = 0;
- double.TryParse(drValue, out doubV);
- newCell.SetCellValue(doubV);
- break;
- case "System.DBNull"://空值处理
- newCell.SetCellValue("");
- break;
- default:
- newCell.SetCellValue("");
- break;
- }
- }
- #endregion
- rowIndex++;
- }
- using (MemoryStream ms = new MemoryStream())
- {
- workbook.Write(ms);
- ms.Flush();
- ms.Position = 0;
- sheet.Dispose();
- //workbook.Dispose();//一般只用写这一个就OK了,他会遍历并释放所有资源,但当前版本有问题所以只释放sheet
- return ms;
- }
- }
- /// <summary>
- /// 用于Web导出
- /// </summary>
- /// <param name="dtSource">源DataTable</param>
- /// <param name="strHeaderText">表头文本</param>
- /// <param name="strFileName">文件名</param>
- /// <Author>柳永法 http://www.yongfa365.com/ 2010-5-8 22:21:41</Author>
- public static void ExportByWeb(DataTable dtSource, string strHeaderText, string strFileName)
- {
- HttpContext curContext = HttpContext.Current;
- // 设置编码和附件格式
- curContext.Response.ContentType = "application/vnd.ms-excel";
- curContext.Response.ContentEncoding = Encoding.UTF8;
- curContext.Response.Charset = "";
- curContext.Response.AppendHeader("Content-Disposition",
- "attachment;filename=" + HttpUtility.UrlEncode(strFileName, Encoding.UTF8));
- curContext.Response.BinaryWrite(Export(dtSource, strHeaderText).GetBuffer());
- curContext.Response.End();
- }
- /// <summary>读取excel
- /// 默认第一行为标头
- /// </summary>
- /// <param name="strFileName">excel文档路径</param>
- /// <returns></returns>
- public static DataTable Import(string strFileName)
- {
- DataTable dt = new DataTable();
- HSSFWorkbook hssfworkbook;
- using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read))
- {
- hssfworkbook = new HSSFWorkbook(file);
- }
- HSSFSheet sheet = hssfworkbook.GetSheetAt(0);
- System.Collections.IEnumerator rows = sheet.GetRowEnumerator();
- HSSFRow headerRow = sheet.GetRow(0);
- int cellCount = headerRow.LastCellNum;
- for (int j = 0; j < cellCount; j++)
- {
- HSSFCell cell = headerRow.GetCell(j);
- dt.Columns.Add(cell.ToString());
- }
- for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
- {
- HSSFRow row = sheet.GetRow(i);
- DataRow dataRow = dt.NewRow();
- for (int j = row.FirstCellNum; j < cellCount; j++)
- {
- if (row.GetCell(j) != null)
- dataRow[j] = row.GetCell(j).ToString();
- }
- dt.Rows.Add(dataRow);
- }
- return dt;
- }
- }