1. 程式人生 > >Excel轉化成DataTable實現:NPOI和OLEDb

Excel轉化成DataTable實現:NPOI和OLEDb

hdr get typeof rop gpo 文件存儲 lis bre excel2003

使用兩種方式實現的excel數據轉化成DataSet,再結合前一篇的DataTable轉化為實體,就可以解決excel到實體之間的轉化。

代碼如下:

首先定義一個接口:

    public interface IExcelAccess
    {
        DataSet Load(ExcelConfig config);
    }
public class ExcelConfig
    {
        /// <summary>
        /// 文件存儲路徑
        /// </summary>
        public
string Path { get; set; } /// <summary> /// 文件表頭所在行索引 /// </summary> public int HeaderIndex { get; set; } }

再來看一下使用NPOI的實現:

public class NpoiExcelAccess : IExcelAccess
    {
        /// <summary>
        /// 根據文件擴展名,獲取workbook實例
        /// </summary>
/// <param name="ext"></param> /// <returns></returns> private IWorkbook GetWorkBook(string ext, Stream stream) { IWorkbook workbook = null; switch (ext) { case ".xlsx": workbook
= new XSSFWorkbook(stream); break; case ".xls": workbook = new HSSFWorkbook(stream); break; default: break; } return workbook; } /// <summary> /// 加載數據,可設置跳過前幾行 /// </summary> /// <param name="path"></param> /// <param name="skipRows"></param> /// <returns></returns> public DataSet Load(ExcelConfig config) { using (var fileStream = new FileStream(config.Path, FileMode.Open, FileAccess.Read)) { var ds = new DataSet(); var ext = Path.GetExtension(config.Path); // 新建IWorkbook對象 var workbook = this.GetWorkBook(ext, fileStream); for (int i = 0; i < workbook.NumberOfSheets; i++) { ISheet sheet = workbook.GetSheetAt(i); DataTable dt = GetDataTable(sheet, config.HeaderIndex); ds.Tables.Add(dt); } return ds; } } private DataTable GetDataTable(ISheet sheet, int headerIndex) { var dt = new DataTable(); // 獲取表頭行 var headerRow = sheet.GetRow(headerIndex); var cellCount = GetCellCount(sheet, headerIndex); // 設置表頭 for (int i = 0; i < cellCount; i++) { if (headerRow.GetCell(i) != null) { dt.Columns.Add(headerRow.GetCell(i).StringCellValue, typeof(string)); } } for (int i = headerIndex + 1; i <= sheet.LastRowNum; i++) { IRow row = sheet.GetRow(i); DataRow dr = dt.NewRow(); FillDataRow(row, ref dr); dt.Rows.Add(dr); } dt.TableName = sheet.SheetName; return dt; } private void FillDataRow(IRow row, ref DataRow dr) { if (row != null) { for (int j = 0; j < dr.Table.Columns.Count; j++) { ICell cell = row.GetCell(j); if (cell != null) { switch (cell.CellType) { case CellType.Blank: dr[j] = DBNull.Value; break; case CellType.Boolean: dr[j] = cell.BooleanCellValue; break; case CellType.Numeric: if (DateUtil.IsCellDateFormatted(cell)) { dr[j] = cell.DateCellValue; } else { dr[j] = cell.NumericCellValue; } break; case CellType.String: dr[j] = cell.StringCellValue; break; case CellType.Error: dr[j] = cell.ErrorCellValue; break; case CellType.Formula: // cell = evaluator.EvaluateInCell(cell) as HSSFCell; dr[j] = cell.ToString(); break; default: throw new NotSupportedException(string.Format("Catched unhandle CellType[{0}]", cell.CellType)); } } } } } /// <summary> /// 獲取表頭列數 /// </summary> /// <param name="sheet"></param> /// <param name="skipRows"></param> /// <returns></returns> private int GetCellCount(ISheet sheet, int headerIndex) { var headerRow = sheet.GetRow(headerIndex); return headerRow.LastCellNum; } }

最後看一下使用OLEDB的實現,這裏,我只實現了excel2003的版本,07版本的總是失敗,查了原因,是需要在本機安裝一個組件才能支持導入.xlsx文件。

 public class OleDbExcelAccess : IExcelAccess
    {
        private string strConn;

        public OleDbExcelAccess()
        {
            //TODO 需要根據擴展名,來決定 使用哪一種連接字符串
            strConn = " Provider = Microsoft.Jet.OLEDB.4.0 ; Data Source = {0};Extended Properties=‘Excel 8.0;IMEX=1;HDR=NO‘";
        }

        public DataSet Load(ExcelConfig config)
        {
            var ds = new DataSet();
            var sheets = GetSheetNames(config.Path);
            var strConnTmp = string.Format(strConn, config.Path);

            foreach (string sheet in sheets)
            {
                using (var oleConn = new OleDbConnection(strConnTmp))
                {
                    var strsql = "SELECT * FROM [" + sheet + "]";
                    var oleDaExcel = new OleDbDataAdapter(strsql, oleConn);
                    oleConn.Open();
                    oleDaExcel.Fill(ds, sheet);
                }
            }

            return ds;
        }

        /// <summary>
        /// 獲取Excel的所有的sheet
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private string[] GetSheetNames(string path)
        {
            DataTable dt = new DataTable();
            if (File.Exists(path))
            {
                string strConnTmp = string.Format(strConn, path);
                using (var conn = new OleDbConnection(strConnTmp))
                {
                    conn.Open();
                    //返回Excel的架構,包括各個sheet表的名稱,類型,創建時間和修改時間等    
                    dt = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "Table" });
                }
                //包含excel中表名的字符串數組
                var sheetNames = new List<string>();
                for (int k = 0; k < dt.Rows.Count; k++)
                {
                    string tableName = dt.Rows[k]["TABLE_NAME"].ToString();
                    //修正出現兼容性視圖名稱時過濾表名
                    if (!tableName.Substring(tableName.Length - 1).Equals("_"))
                    {
                        sheetNames.Add(tableName);
                    }
                }
                return sheetNames.ToArray();

            }
            return null;

        }
    }

最後看一下客戶端的調用 :

 private void TestExcelImport()
        {
            var excelFile = Path.Combine("C:\\Users\\hankk\\Desktop\\ICON", "2003版本.xls");

            ExcelConfig config = new ExcelConfig()
            {
                Path = excelFile,
                HeaderIndex = 1
            };

            IExcelAccess npoiAccess = new NpoiExcelAccess();
            var npoiDs = npoiAccess.Load(config);

            IExcelAccess oleDbAccess = new OleDbExcelAccess();
            var oleDs = oleDbAccess.Load(config);
        }

代碼已上傳到github: https://github.com/hankuikuide/ExcelAccessor

Excel轉化成DataTable實現:NPOI和OLEDb