一、引言
昨天公司EDI导入功能出现问题,经排查是由于引用Com组件Microsoft.Office.Interop.Excel.dll,操作Excel引起,可是现在客户电脑压根都没装Office,还倒个鬼数据啊(画个圈圈xx下之前写这个功能的人),一次重构操作Excel功能之旅由此开始。。。
二、NPOI操作Excel
1.整个Excel(工作薄):WorkBook,包含的页(工作表):Sheet, 行:Row, 单元格:Cell。
2.HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls ;
XSSFWorkbook:是操作Excel2007及以上的版本,扩展名是.xlsx。
3.NPOI组件下载地址:https://npoi.codeplex.com/
4.如果是.NET Framwork环境,请将下载的npoi组件都引用一下,如果是.NET Core环境,就在NuGet程序包中搜索安装 DotNetCore.NPOI 这个程序包即可
5.NPOI源码地址:https://github.com/tonyqus/npoi
下面是NPOI读写Excel的例子,ExcelHelper是自己封装的类库,包括创建Excel,Excel写入txt,Excel写入DataTable,DataTable写入Excel等

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NPOI.HSSF.UserModel;//HSSFWorkbook
using NPOI.SS.UserModel;//ISheet
using System.IO;
using NPOI.XSSF.UserModel;
using System.Data;
namespace NetUtilityLib
{
public class ExcelHelper
{
/// <summary>
/// 基础demo 创建默认版本的excel
/// </summary>
/// <param name="path">需要创建的excel路径</param>
private static void CreateExcel(string path)
{
try
{
#region //操作excel 03版本
//创建工作薄
HSSFWorkbook hssfworkbook = new HSSFWorkbook();
hssfworkbook.CreateSheet("Sheet1");
hssfworkbook.CreateSheet("Sheet2");
hssfworkbook.CreateSheet("Sheet3");
//根据名称获取指定Sheet页
ISheet sheet = hssfworkbook.GetSheet("Sheet1");
//根据索引 创建所在行 row range 0~65535
IRow row = sheet.CreateRow(1);
for (int i = 0; i < 20; i++)
{
ICell cell = row.CreateCell(i);//在行中创建单元格
cell.SetCellValue(i);//向单元格张添加数据
}
//打开excel文件,不存在就创建excel
using (FileStream file = new FileStream(@"F:/test.xls", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
//将工作薄hssfworkbook 写入excel
hssfworkbook.Write(file);
}
#endregion
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw new Exception(ex.Message);
}
}
/// <summary>
/// 创建工作薄
/// </summary>
/// <param name="path">excel路径</param>
/// <param name="workbook">创建的工作薄</param>
/// <returns>创建工作薄是否成功</returns>
private static bool GetWorkbook(string path, out IWorkbook workbook)
{
if (path.IndexOf("xlsx") > 0)
{
workbook = new XSSFWorkbook();//07 及以上
}
else if (path.IndexOf("xls") > 0)
{
workbook = new HSSFWorkbook();//03
}
else
{
workbook = null;
return false;
}
return true;
}
/// <summary>
/// 读取时 创建工作薄
/// </summary>
/// <param name="path">excel的路径</param>
/// <param name="workbook">将数据读进工作薄</param>
/// <param name="fs">数据流</param>
/// <returns>数据是否能够读进excel中</returns>
private static bool GetWorkbook(string path, out IWorkbook workbook, FileStream fs)
{
if (path.IndexOf("xlsx") > 0)
{
workbook = new XSSFWorkbook(fs);//07 及以上
}
else if (path.IndexOf("xls") > 0)
{
workbook = new HSSFWorkbook(fs);//03
}
else
{
workbook = null;
return false;
}
return true;
}
/// <summary>
/// 创建一个excel
/// </summary>
/// <param name="path">要创建的excel路径及名称</param>
/// <param name="sheetNames">要创建的excel的sheet页名称集合</param>
/// <returns>创建是否成功</returns>
public static bool CreateExcel(string path, IList<string> sheetNames)
{
try
{
IWorkbook workbook = null;
FileStream fs = null;
if (!GetWorkbook(path, out workbook)) { return false; }
if (sheetNames.Count > 0)
{
foreach (string sheetName in sheetNames)
{
workbook.CreateSheet(sheetName);
}
}
else
{
workbook.CreateSheet("Sheet1");
workbook.CreateSheet("Sheet2");
workbook.CreateSheet("Sheet3");
}
using (fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
workbook.Write(fs);
}
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw new Exception(ex.Message);
}
}
/// <summary>
/// 将excel中数据导入到txt中
/// </summary>
/// <param name="excelPath">要导出的excel路径及名称</param>
/// <param name="txtPath">要导入的txtl路径及名称</param>
/// <returns>是否导入txt成功</returns>
public static bool ExcelToTxt(string excelPath, string txtPath)
{
try
{
IWorkbook workbook = null;
FileStream fs = null;
object cellValue = DBNull.Value;
StringBuilder sbr = new StringBuilder();
using (fs = new FileStream(excelPath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
if (!GetWorkbook(excelPath, out workbook, fs)) { return false; }
for (int i = 0; i < workbook.NumberOfSheets; i++) //NumberOfSheets是excel中总共的表数
{
ISheet sheet = workbook.GetSheetAt(i); //读取当前表数据
for (int j = 0; j <= sheet.LastRowNum; j++) //LastRowNum 是当前表的总行数
{
IRow row = sheet.GetRow(j); //读取当前行数据
if (row != null)
{
sbr.Append("\r\n");//换行
for (int k = 0; k <= row.LastCellNum; k++) //LastCellNum 是当前行的总列数
{
ICell cell = row.GetCell(k); //当前表格
if (cell != null)
{
cellValue = GetCellValue(cell);
}
sbr.Append(cellValue + "\t"); //获取表格中的数据
cellValue = DBNull.Value;
}
}
}
}
}
sbr.ToString();
using (StreamWriter wr = new StreamWriter(new FileStream(txtPath, FileMode.Append))) //把读取excel文件的数据写入txt文件中
{
wr.Write(sbr.ToString());
wr.Flush();
}
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw new Exception(ex.Message);
}
}
/// <summary>
/// 将excel中的数据导入到DataTable中
/// </summary>
/// <param name="data">要导入的excel路径及名称</param>
/// <param name="sheetName">excel工作薄sheet的名称</param>
/// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param>
/// <returns>返回的DataTable</returns>
public static DataTable ExcelToDataTable(string excelPath, string sheetName, bool isFirstRowColumn)
{
IWorkbook workbook = null;
ISheet sheet = null;
FileStream fs = null;
object cellValue = DBNull.Value;
DataTable data = new DataTable();
int startRow = 0;
try
{
using (fs = new FileStream(excelPath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
if (!GetWorkbook(excelPath, out workbook, fs)) { return null; }
if (sheetName != null)
{
sheet = workbook.GetSheet(sheetName);
if (sheet == null) //如果没有找到指定的sheetName对应的sheet,则尝试获取第一个sheet
{
sheet = workbook.GetSheetAt(0);
}
}
else
{
sheet = workbook.GetSheetAt(0);
}
if (sheet != null)
{
IRow firstRow = sheet.GetRow(0);
int cellCount = firstRow.LastCellNum; //一行最后一个cell的编号 即总的列数
if (isFirstRowColumn)
{
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
{
ICell cell = firstRow.GetCell(i);
if (cell != null)
{
cellValue = GetCellValue(cell);
if (cellValue != null)
{
DataColumn column = new DataColumn(cellValue.ToString());
data.Columns.Add(column);
}
}
}
startRow = sheet.FirstRowNum + 1;
}
else
{
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
{
DataColumn column = new DataColumn();
data.Columns.Add(column);
}
startRow = sheet.FirstRowNum;
}
//最后一列的标号
int rowCount = sheet.LastRowNum;
for (int i = startRow; i <= rowCount; ++i)
{
IRow row = sheet.GetRow(i);
if (row == null) continue; //没有数据的行默认是null
DataRow dataRow = data.NewRow();
for (int j = row.FirstCellNum; j < cellCount; ++j)
{
dataRow[j] = row.GetCell(j) == null ? DBNull.Value : GetCellValue(row.GetCell(j));
}
data.Rows.Add(dataRow);
}
}
}
return data;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Exception: " + ex.Message);
return null;
}
}
/// <summary>
/// 将DataTable数据导入到excel中
/// </summary>
/// <param name="data">要导入的excel路径及名称</param>
/// <param name="data">要导入的数据</param>
/// <param name="isColumnWritten">DataTable的列名是否要导入</param>
/// <param name="sheetName">要导入的excel的sheet的名称</param>
/// <returns>导入数据行数(包含列名那一行)</returns>
public static int DataTableToExcel(string excelPath, DataTable data, string sheetName, bool isColumnWritten)
{
int i = 0;
int j = 0;
int count = 0;
IWorkbook workbook = null;
ISheet sheet = null;
FileStream fs = null;
try
{
using (fs = new FileStream(excelPath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
if (!GetWorkbook(excelPath, out workbook)) { return -1; }
sheetName = sheetName != "" ? sheetName : "Sheet1";
sheet = workbook.CreateSheet(sheetName);
if (isColumnWritten == true) //写入DataTable的列名
{
IRow row = sheet.CreateRow(0);
for (j = 0; j < data.Columns.Count; ++j)
{
row.CreateCell(j).SetCellValue(data.Columns[j].ColumnName);
}
count = 1;
}
else
{
count = 0;
}
for (i = 0; i < data.Rows.Count; ++i)
{
IRow row = sheet.CreateRow(count);
for (j = 0; j < data.Columns.Count; ++j)
{
row.CreateCell(j).SetCellValue(data.Rows[i][j].ToString());
}
++count;
}
workbook.Write(fs); //写入到excel
return count;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Exception: " + ex.Message);
return -1;
}
}
/// <summary>
/// 获取excel中单元格的数据
/// </summary>
/// <param name="pCell">获取到的单元格</param>
/// <returns>单元格中数据</returns>
private static object GetCellValue(ICell pCell)
{
object objReturn;
try
{
switch (pCell.CellType)
{
case CellType.Blank:
objReturn = DBNull.Value;
break;
//case CellType.Boolean:
// break;
//case CellType.Error:
// break;
case CellType.Formula:
objReturn = TryReturn(pCell);
break;
case CellType.Numeric:
if (pCell.CellStyle.DataFormat == 14 || pCell.CellStyle.DataFormat == 22 || pCell.CellStyle.DataFormat == 165 || pCell.CellStyle.DataFormat == 164 || pCell.CellStyle.DataFormat == 191 || pCell.CellStyle.DataFormat == 195)//14为日期类型
{
//来自Excel单元格的数据如果能转为日期类型,则取DateCellValue 不可以则NumericCellValue
DateTime dtCellValue;
if (DateTime.TryParse(pCell.ToString(), out dtCellValue))
{
if (pCell.ToString().IndexOf(",") > -1)
objReturn = pCell.NumericCellValue;
else
objReturn = pCell.DateCellValue;
}
else
{
objReturn = pCell.NumericCellValue;
}
}
else
{
objReturn = pCell.NumericCellValue;
}
break;
case CellType.String:
objReturn = pCell.StringCellValue;
break;
//case CellType.Unknown:
// break;
default:
objReturn = pCell.ToString();
break;
}
return objReturn;
}
catch (Exception)
{
objReturn = pCell.ToString();
}
return objReturn;
}
/// <summary>
/// 用于容错,当NumericCellValue出现异常时,默认取StringCellValue的值.
/// </summary>
/// <param name="pCell"></param>
/// <returns></returns>
private static object TryReturn(ICell pCell)
{
object objReturn;
try
{
objReturn = pCell.NumericCellValue;
return objReturn;
}
catch
{
objReturn = pCell.StringCellValue;
return objReturn;
}
}
}
}
源代码已上传至:https://github.com/jdzhang1221/NetUtilityLib
写在后面:
如果你是大牛,请多多批评指正文中不足;
如果你和博主一样是小白,请点下右下角推荐,因为你的支持是我坚持不懈的动力;
如感兴趣请多提宝贵意见,大家互相学习,共同进步!
参考:
http://www.cnblogs.com/savorboard/p/dotnetcore-npoi.html
http://www.cnblogs.com/knowledgesea/archive/2012/11/16/2772547.html
http://www.cnblogs.com/luxiaoxun/p/3374992.html
https://github.com/tonyqus/npoi
来源:https://www.cnblogs.com/jdzhang/p/7458095.html
