這篇會介紹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(1); for (int i = 0; i < 20; 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 = 0; i < wk.NumberOfSheets; i++) //NumberOfSheets是myxls.xls中總共的表數 { ISheet sheet = wk.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) { 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 = 0; i < wk.NumberOfSheets; i++) //NumberOfSheets是myxls.xls中總共的表數 { ISheet sheet = wk.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) { 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 = 0; 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 = 0; i < iLastRowNum; i++) { row = sheet.GetRow(i); if (row == null) { continue; } for (int j = 0; 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 = 0; 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 > 0) { 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 + 2).ToString().Trim(); //表的英文名稱 mTable.Code = sheet.GetRow(iRow + 1).GetCell(iCell + 2).ToString().Trim(); //表的描述 mTable.Comment = mTable.Name; //標題列 2014-05-03杜冬軍修改,動態讀取列,確保列順序 var row = sheet.GetRow(iRow+3); //緩存列索引和名稱 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 + 4; 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 + 1; row = sheet.GetRow(iRow); } else { break; } } if (string.IsNullOrEmpty(mTable.Comment)) { mTable.Comment = mTable.Name; } if (mTable.ListPkKeyInfo != null && mTable.ListPkKeyInfo.Count > 0) { foreach (PkKeyInfo pkInfo in mTable.ListPkKeyInfo) { mTable.PkKeyNameList = mTable.PkKeyNameList + pkInfo.Name + ","; } } if (!string.IsNullOrEmpty(mTable.PkKeyNameList)) { mTable.PkKeyNameList = mTable.PkKeyNameList.Substring(0, mTable.PkKeyNameList.Length - 1); } 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 + 1; 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群。
更多數據字典生成工具資料請點擊數據字典生成工具專題。