笔者最近遇到一个项目,需要做一个SSIS Package,修改Excel的列名,并在ssms中创建job自动执行,项目需求比较简单,由于笔者做过的Package比较少,所以经历了一番曲折。
我首先想到的是使用NPOI,在Script task中使用NPOI.dll,但是在使用NPOI时,Script task不能将NPOI自动导入到.net framework,需要执行一个gacutil的脚本,有点麻烦,放弃。
其次,我想到 Microsoft.Office.Interop.Excel.dll ,这个类库是MS提供的用于操作Excel的类库,既然Microsoft.Office.Interop.Excel.dll是微软的东西,肯定是已经集成到.net framework中,免去了导入的麻烦。但是在Script Task中使用Microsoft.Office.Interop.Excel.dll仍然出错,这可能跟Script Task 的内部实现机制有关系,不允许创建Excel的process,放弃。
然后,我使用了Execute Process Task 来引用一个Console Application,在BIDS中调试运行是没有任何问题的,但是在SSMS中排job,job不能正常执行,返回异常,并且不能Kill Excel的Prcess,长久下去,Excel的process会耗尽所有的内存,放弃。
最后,还是决定使用Execute Process Task来引用一个Console Application,使用NPOI来操作Excel,最终解决了问题。
以下示例代码就是使用NPOI的Console Application,是项目的一段测试代码的,主要实现的功能修改Excel的ColumnName,并从Excel的两个sheet中读取数据到DataTable中。
class Program { static Hashtable ht1 = new Hashtable(); static Hashtable ht2 = new Hashtable(); static DataTable dt = new DataTable("dt"); static string strExcelPath = @"C:\ExcelFile\test.xlsx"; static void Main(string[] args) { Console.Write("begin"); GetDataFromExcel(); Console.Write("end"); System.Console.Read(); } static void CreateDataTable() { dt.Columns.Add("XCode"); dt.Columns.Add("DescriptionOrg"); dt.Columns.Add("Country"); dt.Columns.Add("tx"); dt.Columns.Add("BG"); dt.Columns.Add("Cell"); dt.Columns.Add("Sheet", typeof(int)); } public static void SetMapFromExcelHeadColumn(int sheet,string key,int keyIdx) { int idx = 0; if (sheet==1) { switch(key.Trim().ToLower()) { case "country": idx = 2; break; case "x-code": idx = 0; break; case "bg": idx = 4; break; case "description": idx = 1; break; case "tx": idx = 3; break; default: idx = 7; break; } ht1.Add(keyIdx, idx); } else { switch (key.Trim().ToLower()) { case "country": idx = 2; break; case "xcode": idx = 0; break; case "cell": idx = 5; break; default: idx = 7; break; } ht2.Add(keyIdx, idx); } } static public void GetDataFromExcel() { XSSFWorkbook workbook; using (FileStream file = new FileStream(strExcelPath, FileMode.Open, FileAccess.Read)) { workbook = new XSSFWorkbook(file); file.Close(); file.Dispose(); } CreateDataTable(); //read sheet1 ISheet sheet = workbook.GetSheetAt(0); int iRowCnt, iCellCnt; iRowCnt = sheet.LastRowNum; //iCellCnt = sheet.GetRow(0).LastCellNum; iCellCnt = 9; for(int i=0;i<iCellCnt;i++) { SetMapFromExcelHeadColumn(1,sheet.GetRow(0).Cells[i].StringCellValue.Trim().ToLower(),i); } for (int i = 1; i < iRowCnt; i++) { IRow row = sheet.GetRow(i); DataRow dr = dt.NewRow(); for (int j = 0; j < iCellCnt; j++) { ICell cell = row.GetCell(j); if (cell == null) continue; string strCellValue=cell.ToString(); int idx=(int)ht1[j]; if(idx<7) { dr[idx] = strCellValue; } } dr[6] = "1"; dt.Rows.Add(dr); } //read sheet2 sheet = workbook.GetSheetAt(1); iRowCnt = sheet.LastRowNum; //iCellCnt = sheet.GetRow(0).LastCellNum; iCellCnt = 4; for(int i=0;i<iCellCnt;i++) { SetMapFromExcelHeadColumn(2,sheet.GetRow(0).Cells[i].ToString().Trim().ToLower(),i+1); } for (int i = 1; i < iRowCnt; i++) { IRow row = sheet.GetRow(i); DataRow dr = dt.NewRow(); for (int j = 0; j < iCellCnt; j++) { ICell cell = row.GetCell(j); if (cell == null) continue; string strCellValue = cell.ToString(); int idx = (int)ht2[j]; if (idx < 7) { dr[idx] = strCellValue; } } dr[6] = "2"; dt.Rows.Add(dr); } int iTotalRowCnt = dt.Rows.Count; } public static void UpdateExcelColumnNameSimplify() { XSSFWorkbook workbook; using (FileStream file = new FileStream(strExcelPath, FileMode.Open, FileAccess.ReadWrite)) { workbook = new XSSFWorkbook(file); File.Delete(strExcelPath); file.Close(); file.Dispose(); } ISheet sheet = workbook.GetSheetAt(0); IRow row = sheet.GetRow(0); for (int j = 0; j < row.LastCellNum; j++) { ICell cell = row.GetCell(j); if (cell == null) continue; cell.SetCellValue(cell.ToString().Trim()); } sheet = workbook.GetSheetAt(1); row = sheet.GetRow(0); for (int j = 0; j < row.LastCellNum; j++) { ICell cell = row.GetCell(j); if (cell == null) continue; cell.SetCellValue(cell.ToString().Trim()); } using (FileStream file = new FileStream(strExcelPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { workbook.Write(file); file.Close(); file.Dispose(); } } }