这篇会介绍NPOI读写EXECL,读写EXECL的组件很多,可以使用微软自己的COM组件EXECL.exe读写,不过这种方式限制很大。
1:客户环境必须装Office(虽然现在机子上不装Office的几乎没有吧)
2:EXECL读写完毕后EXECL还有进程还留在后台 ,内存回收不了
基于以上的原因,就采用了开源组件NPOI进行操作了。
阅读目录
NPOI简介
1.Excel表格叫做工作表:WorkBook(工作薄),包含的叫页(工作表):Sheet;行:Row;单元格Cell。
2.Npoi 下载地址:http://npoi.codeplex.com
3.Npoi 学习系列教程推荐:http://tonyqus.sinaapp.com
4.npoi 能够读写几乎所有的Office 97-2010文件格式(特别提示读取EXECL2007版本及以上的需要使用NPOI2.0版本才行,也就是.xlsx。之前EXECL老版本是.xls),至少能够支持Word, PowerPoint, Excel, Visio的格式。
简单示例
1.创建一个简单的xls文件
//创建xls文件
private void button1_Click(object sender, EventArgs e)
{
//创建工作薄
HSSFWorkbook wk = new HSSFWorkbook();
//创建一个名称为mySheet的表
ISheet tb = wk.CreateSheet("mySheet");
//创建一行,此行为第二行
IRow row = tb.CreateRow();
for (int i = ; i < ; i++)
{
ICell cell = row.CreateCell(i); //在第二行中创建单元格
cell.SetCellValue(i);//循环往第二行的单元格中添加数据
}
using (FileStream fs = File.OpenWrite(@"c:/myxls.xls")) //打开一个xls文件,如果没有则自行创建,如果存在myxls.xls文件则在创建是不要打开该文件!
{
wk.Write(fs); //向打开的这个xls文件中写入mySheet表并保存。
MessageBox.Show("提示:创建成功!");
}
}
2.读取简单的xls文件
/// <summary>
/// 读取一个简单xls文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
StringBuilder sbr = new StringBuilder();
string path = GetDeskTopPath() + @"\myxls.xls";
using (FileStream fs = File.OpenRead(path)) //打开myxls.xls文件
{
HSSFWorkbook wk = new HSSFWorkbook(fs); //把xls文件中的数据写入wk中
for (int i = ; i < wk.NumberOfSheets; i++) //NumberOfSheets是myxls.xls中总共的表数
{
ISheet sheet = wk.GetSheetAt(i); //读取当前表数据
for (int j = ; j <= sheet.LastRowNum; j++) //LastRowNum 是当前表的总行数
{
IRow row = sheet.GetRow(j); //读取当前行数据
if (row != null)
{
sbr.Append("-------------------------------------\r\n"); //读取行与行之间的提示界限
for (int k = ; k <= row.LastCellNum; k++) //LastCellNum 是当前行的总列数
{
ICell cell = row.GetCell(k); //当前表格
if (cell != null)
{
sbr.Append(cell.ToString()); //获取表格中的数据并转换为字符串类型
}
}
}
}
}
}
sbr.ToString();
path = GetDeskTopPath() + @"\myText.txt";
using (StreamWriter wr = new StreamWriter(new FileStream(path, FileMode.Append))) //把读取xls文件的数据写入myText.txt文件中
{
wr.Write(sbr.ToString());
wr.Flush();
MessageBox.Show("提示:写入成功!");
}
}
3.读取EXECL文件,兼容xls和xlsx文件,NPOI2.0特意为这种情况提供接口读取,免去用户需要判断文件格式写不同代码的烦恼,看下面的实例
StringBuilder sbr = new StringBuilder();
string path = GetDeskTopPath() + @"\myxls.xls";
using (FileStream fs = File.OpenRead(path)) //打开myxls.xls文件
{
IWorkbook wk = WorkbookFactory.Create(fs); //使用接口,自动识别excel2003/2007格式
for (int i = ; i < wk.NumberOfSheets; i++) //NumberOfSheets是myxls.xls中总共的表数
{
ISheet sheet = wk.GetSheetAt(i); //读取当前表数据
for (int j = ; j <= sheet.LastRowNum; j++) //LastRowNum 是当前表的总行数
{
IRow row = sheet.GetRow(j); //读取当前行数据
if (row != null)
{
sbr.Append("-------------------------------------\r\n"); //读取行与行之间的提示界限
for (int k = ; k <= row.LastCellNum; k++) //LastCellNum 是当前行的总列数
{
ICell cell = row.GetCell(k); //当前表格
if (cell != null)
{
sbr.Append(cell.ToString()); //获取表格中的数据并转换为字符串类型
}
}
}
}
}
}
sbr.ToString();
path = GetDeskTopPath() + @"\myText.txt";
using (StreamWriter wr = new StreamWriter(new FileStream(path, FileMode.Append))) //把读取xls文件的数据写入myText.txt文件中
{
wr.Write(sbr.ToString());
wr.Flush();
MessageBox.Show("提示:写入成功!");
}
上面表红部分是读取文件的接口,需要着重注意。NPOI提供WorkbookFactroy工厂类。另外创建xlxs文件方法类似,唯一区别使用XSSFWorkbook创建WorkBook对象。
XSSFWorkbook wk = new XSSFWorkbook();
NPOI在本工具的使用及总结
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel; namespace MyTools.DataDic.Utils
{
/// <summary>
/// 解析Execl文件,读取信息
/// </summary>
public class ExeclReader : IReader
{
/// <summary>
/// Execl文件路径
/// </summary>
private string _pdmPath; private List<TableInfo> mTables = null; private IWorkbook hssfworkbook = null; /// <summary>
/// 校验文件路径是否存在
/// </summary>
/// <param name="pdmPath">EXECL文件路径</param>
private void CheckPath(string pdmPath)
{
if (string.IsNullOrEmpty(pdmPath))
{
throw new Exception("文件路径不能为空!");
}
if (!pdmPath.EndsWith(".xls", true, null) && !pdmPath.EndsWith(".xlsx", true, null))
{
throw new Exception("文件格式不正确,请选择EXECL文件!");
}
if (!File.Exists(pdmPath))
{
throw new Exception("指定文件不存在!");
}
} /// <summary>
/// 构造函数 根据路径生成所有表的SQL
/// </summary>
/// <param name="pdmPath">EXECL文件路径</param>
public ExeclReader(string pdmPath)
{
try
{
CheckPath(pdmPath);
_pdmPath = pdmPath;
}
catch (Exception ex)
{
throw ex;
}
} /// <summary>
/// 初始化EXECL
/// </summary>
/// <returns>HSSFWorkbook</returns>
private IWorkbook InitHSSFWorkbook()
{
if (hssfworkbook == null)
{
try
{
using (FileStream fs = new FileStream(_pdmPath, FileMode.Open, FileAccess.Read))
{
hssfworkbook = WorkbookFactory.Create(fs);
}
}
catch (Exception e)
{
throw e;
}
}
return hssfworkbook;
} /// <summary>
/// 从EXECL读取表信息
/// </summary>
/// <returns> List</returns>
public List<TableInfo> GetTableInfo()
{
try
{
IWorkbook hssfworkbook = InitHSSFWorkbook();
List<TableInfo> Tables = new List<TableInfo>();
//杜冬军2014-05-03修改 循环读取EXECL所有的非隐藏Sheet
//sheet总数
int iSheetNum=hssfworkbook.NumberOfSheets;
ISheet sheet = null;
for (int m = ; m < iSheetNum; m++)
{
if (hssfworkbook.IsSheetHidden(m))
{
continue;
}
sheet = hssfworkbook.GetSheetAt(m);
IRow row = null;
ICell cell = null;
int iLastRowNum = sheet.LastRowNum;
for (int i = ; i < iLastRowNum; i++)
{
row = sheet.GetRow(i);
if (row == null)
{
continue;
}
for (int j = ; j < row.LastCellNum; j++)
{
//列索引异常BUG修复 2014-06-07杜冬军修改 row.Cells不适合
cell = row.GetCell(j);
if (cell != null && cell.ToString().Trim() == "数据表中文名称")
{
i = GetTable(sheet, i, cell.ColumnIndex, Tables, sheet.SheetName.Trim());
break;
}
}
}
}
mTables = Tables;
return Tables;
}
catch (Exception ex)
{
throw ex;
}
} /// <summary>
/// 从中读取物理图信息
/// </summary>
/// <returns> List</returns>
public List<PhysicalDiagramInfo> GetPDInfo()
{
try
{
List<PhysicalDiagramInfo> PDList = new List<PhysicalDiagramInfo>();
IWorkbook hssfworkbook = InitHSSFWorkbook();
if (mTables == null)
{
mTables = GetTableInfo();
}
PhysicalDiagramInfo pdInfo = new PhysicalDiagramInfo();
string pid = System.Guid.NewGuid().ToString();
pdInfo.Id = pid;
pdInfo.Name = "所有数据";
PDList.Add(pdInfo); int iSheetNum=hssfworkbook.NumberOfSheets;
for (int m = ; m < iSheetNum; m++)
{
if (hssfworkbook.IsSheetHidden(m))
{
continue;
}
PhysicalDiagramInfo pd = new PhysicalDiagramInfo();
string pid1 = System.Guid.NewGuid().ToString();
pd.Id = pid1;
pd.Name = hssfworkbook.GetSheetAt(m).SheetName.Trim();
pd.PhyParentId = pid;
PDList.Add(pd);
List<TableInfo> query = (from a in mTables
where a.PDName == pd.Name
select a).ToList<TableInfo>(); foreach (TableInfo t in query)
{
pd = new PhysicalDiagramInfo();
pd.Id = System.Guid.NewGuid().ToString();
pd.Name = t.Code;
pd.IfEnd = true;
pd.PhyParentId = pid1;
PDList.Add(pd); }
}
return PDList;
}
catch (Exception ex)
{
throw ex;
}
} /// <summary>
/// 获取表信息
/// </summary>
/// <param name="tableName">表名</param>
/// <returns>表信息</returns>
public List<TableInfo> GetTableColumnName(string tableName)
{
if (string.IsNullOrEmpty(tableName))
{
throw new Exception("参数空异常!");
}
List<TableInfo> list = GetTableInfo();
if (list != null && list.Count > )
{
IEnumerable<TableInfo> query =
from c in list
where c.Code == tableName
select c;
return query.ToList<TableInfo>();
}
return null;
} /// <summary>
/// 获取节点中表的信息
/// </summary>
/// <param name="sheet">sheet</param>
/// <param name="iRow">iRow</param>
/// <param name="iCell">iCell</param>
/// <param name="sheetName">sheetName</param>
/// <returns>表信息</returns>
private int GetTable(ISheet sheet, int iRow, int iCell, List<TableInfo> Tables,string sheetName)
{
try
{
TableInfo mTable = new TableInfo();
List<ColumnInfo> list = new List<ColumnInfo>();
List<PkKeyInfo> listPkKeyInfo = new List<PkKeyInfo>();
mTable.ListColumnInfo = list;
mTable.ListPkKeyInfo = listPkKeyInfo;
mTable.PDName = sheetName;
//表的ID
mTable.TableObjectID = Guid.NewGuid().ToString();
//表的中文名称
mTable.Name = sheet.GetRow(iRow).GetCell(iCell + ).ToString().Trim();
//表的英文名称
mTable.Code = sheet.GetRow(iRow + ).GetCell(iCell + ).ToString().Trim();
//表的描述
mTable.Comment = mTable.Name; //标题列 2014-05-03杜冬军修改,动态读取列,确保列顺序
var row = sheet.GetRow(iRow+);
//缓存列索引和名称
Dictionary<int, string> dic = new Dictionary<int, string>();
for (int i = iCell; i < row.LastCellNum; i++)
{
dic.Add(i, row.GetCell(i).ToString().Trim());
} iRow = iRow + ;
row = sheet.GetRow(iRow);
while (row != null)
{
if (row.GetCell(iCell) != null && !String.IsNullOrEmpty(row.GetCell(iCell).ToString()))
{
InitColumns(row, iCell, mTable,dic);
iRow = iRow + ;
row = sheet.GetRow(iRow);
}
else
{
break;
} } if (string.IsNullOrEmpty(mTable.Comment))
{
mTable.Comment = mTable.Name;
}
if (mTable.ListPkKeyInfo != null && mTable.ListPkKeyInfo.Count > )
{
foreach (PkKeyInfo pkInfo in mTable.ListPkKeyInfo)
{
mTable.PkKeyNameList = mTable.PkKeyNameList + pkInfo.Name + ",";
}
}
if (!string.IsNullOrEmpty(mTable.PkKeyNameList))
{
mTable.PkKeyNameList = mTable.PkKeyNameList.Substring(, mTable.PkKeyNameList.Length - );
}
Tables.Add(mTable);
return iRow;
}
catch (Exception ex)
{
throw ex;
}
} /// <summary>
/// 获取表中的列信息
/// </summary>
/// <param name="row">列节点</param>
/// <param name="iCell">列起始索引</param>
/// <param name="pTable">表信息</param>
/// <param name="dic">列名字典集合</param>
private void InitColumns(IRow row, int iCell, TableInfo pTable, Dictionary<int, string> dic)
{
ColumnInfo mColumn = new ColumnInfo();
//列ID
mColumn.ColumnObjectId = Guid.NewGuid().ToString();
string sTemp = "";
int LastCellIndex = dic.Keys.Last<int>();
for (int i = dic.Keys.First<int>(); i <= LastCellIndex; i++)
{
//2014-07-01杜冬军修改,row.LastCellNum取出来有误,确保不出现空异常
sTemp = row.GetCell(i) == null ? "" : row.GetCell(i).ToString().Trim();
Common.GetColumnInfo(dic, sTemp, mColumn, i, pTable);
}
mColumn.DataTypeStr = Common.GetDataTypeStr(mColumn.DataTypeStr, mColumn.Width);
mColumn.Width = Common.GetColumnWidth(mColumn.DataTypeStr); if (string.IsNullOrEmpty(mColumn.Comment))
{
mColumn.Comment = mColumn.Name;
}
if (string.IsNullOrEmpty(mColumn.DefaultValue))
{
mColumn.DefaultValue = "";
}
mColumn.Sequence = pTable.ListColumnInfo.Count + ;
pTable.ListColumnInfo.Add(mColumn);
}
}
}
上述代码的实现逻辑
使用NPOI操作EXECL还是很方便的,2.0发布以后支持xlxs文件了,功能更加强大,其实EXECL和WORD的文件结构都是xml文件,只不过是相当复杂的。
NPOI帮我们封装好了这些差异方便使用。工具读取WORD文件之前也是采用NPOI组件,但是性能上存在问题,并且WORD单元格的合并很不好操作,最终采用了
DocX组件来替换它,性能真的提升很多,希望NPOI后面的版本能更好的支持WORD吧。这篇到这里就结束了,敬请期待下一篇DocX操作WORD。
文中的实例提供下载:NPOIDemo
工具源代码下载
目前总共有经过了七个版本的升级,现在提供最新版本的下载地址
数据字典生成工具V2.0安装程序 | 最新安装程序 | |
数据字典生成工具源代码 | 最新源代码 | |
http://code.taobao.org/svn/DataDicPub | SVN最新源码共享地址 |
学习使用
如果你使用了该工具,或者想学习该工具,欢迎加入这个小组,一起讨论数据字典生成工具、把该工具做的更强,更方便使用,一起加入147425783 QQ群。
更多数据字典生成工具资料请点击数据字典生成工具专题。