首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

讀取 Excel 內容並實現資料批量上傳

     編輯:關於.NET

業務場景:企業應用中的批量匯入需求

企業應用中常遇到批量上傳資料的需求:客戶使用 Excel 表格錄入大量資料,透過網頁上傳 Excel 檔案,系統自動讀取並批量導入資料庫。核心流程包含三步:讀取 Excel 內容 → 必要欄位驗證 → 導入驗證通過的資料、回報失敗行號與錯誤訊息。

技術選型:為何選擇第三方元件 Koogra

讀取 Excel 的方案眾多,常見有 OLEDB 與第三方元件。考慮到生產環境伺服器不一定安裝 Office 或 OLEDB 提供者,為追求最大相容性,筆者選擇開源元件 Koogra(.NET 實作,SourceForge 專案:https://sourceforge.net/projects/koogra/)。

封裝目標:四種通用呼叫方式,統一回傳 DataTable

  1. 檔案路徑 + 工作表名稱
  2. 檔案路徑 + 工作表索引(0 為第一張表)
  3. 記憶體流 + 工作表名稱
  4. 記憶體流 + 工作表索引

核心程式碼:ExcelUtils 工具類

專案需參考 Ionic.Utils.Zip.dll 與 Net.SourceForge.Koogra.dll。

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Net.SourceForge.Koogra.Excel;

namespace Gren.Framework.Office
{
    /// 
    /// Excel 工具類,封裝 Koogra 實現多樣化讀取
    /// 
    public class ExcelUtils
    {
        private Workbook book;

        public ExcelUtils(string path)
        {
            this.book = new Workbook(path);
        }

        public ExcelUtils(System.IO.Stream stream)
        {
            this.book = new Workbook(stream);
        }

        /// 
        /// 將工作表轉換為 DataTable
        /// 
        protected DataTable SaveAsDataTable(Worksheet sheet)
        {
            DataTable dt = new DataTable();
            uint minRow = sheet.Rows.MinRow;
            uint maxRow = sheet.Rows.MaxRow;
            Row firstRow = sheet.Rows[minRow];
            uint minCol = firstRow.Cells.MinCol;
            uint maxCol = firstRow.Cells.MaxCol;

            // 以第一行作為欄位名
            for (uint i = minCol; i <= maxCol; i++)
                dt.Columns.Add(firstRow.Cells[i].FormattedValue());

            // 從第二行開始讀取資料
            for (uint i = minRow + 1; i <= maxRow; i++)
            {
                Row row = sheet.Rows[i];
                if (row != null)
                {
                    DataRow dr = dt.NewRow();
                    for (uint j = minCol; j <= maxCol; j++)
                    {
                        Cell cell = row.Cells[j];
                        if (cell != null)
                            dr[Convert.ToInt32(j)] = cell.Value != null ? cell.Value.ToString() : string.Empty;
                    }
                    dt.Rows.Add(dr);
                }
            }
            return dt;
        }

        public DataTable ToDataTable(int index)
        {
            Worksheet sheet = this.book.Sheets[index];
            if (sheet == null)
                throw new ApplicationException(string.Format("索引[{0}]所指定的工作表不存在!", index));
            return this.SaveAsDataTable(sheet);
        }

        public DataTable ToDataTable(string sheetName)
        {
            Worksheet sheet = this.book.Sheets.GetByName(sheetName);
            if (sheet == null)
                throw new ApplicationException(string.Format("名稱[{0}]所指定的工作表不存在!", sheetName));
            return this.SaveAsDataTable(sheet);
        }

        #region 靜態便捷方法
        /// 
        /// Excel 日期儲存格(double)轉 DateTime,失敗嘗試字串解析
        /// 
        public static DateTime ParseDateTime(string cellValue)
        {
            DateTime date = default(DateTime);
            double value = default(double);
            if (double.TryParse(cellValue, out value))
                date = DateTime.FromOADate(value);
            else
                DateTime.TryParse(cellValue, out date);
            return date;
        }

        public static DataTable TranslateToTable(string path, string sheetName)
        {
            ExcelUtils utils = new ExcelUtils(path);
            return utils.ToDataTable(sheetName);
        }

        public static DataTable TranslateToTable(string path, int sheetIndex)
        {
            ExcelUtils utils = new ExcelUtils(path);
            return utils.ToDataTable(sheetIndex);
        }

        public static DataTable TranslateToTable(string path)
        {
            ExcelUtils utils = new ExcelUtils(path);
            return utils.ToDataTable(0);
        }

        public static DataTable TranslateToTable(System.IO.Stream stream, string sheetName)
        {
            ExcelUtils utils = new ExcelUtils(stream);
            return utils.ToDataTable(sheetName);
        }

        public static DataTable TranslateToTable(System.IO.Stream stream, int sheetIndex)
        {
            ExcelUtils utils = new ExcelUtils(stream);
            return utils.ToDataTable(sheetIndex);
        }

        public static DataTable TranslateToTable(System.IO.Stream stream)
        {
            ExcelUtils utils = new ExcelUtils(stream);
            return utils.ToDataTable(0);
        }
        #endregion
    }
}

關鍵點解析:ParseDateTime 處理日期儲存格

Excel 中日期型別儲存為 double(OADate 格式),ParseDateTime 先嘗試 double 轉換,失敗再嘗試字串解析(應對使用者將儲存格設為文字格式直接輸入日期的情況)。

ASP.NET 頁面實際呼叫範例

以 fileUpload1 為檔案上傳控件,採用記憶體流處理上傳檔案,效能較佳:

if (fileUpload1.HasFile)
{
    DataTable dt = null;
    try
    {
        using (System.IO.MemoryStream stream = new System.IO.MemoryStream(fileUpload1.FileBytes))
        {
            dt = Gren.Framework.Office.ExcelUtils.TranslateToTable(stream, "sheet1");
        }
        // 取得 DataTable 後,執行自有驗證與入庫邏輯
    }
    catch (Exception ex)
    {
        lblMessage.Text = "

處理資料檔案錯誤:

"; lblMessage.Text += "
" + Server.HtmlEncode(ex.Message) + "
"; } } else { lblMessage.Text = "

請選擇資料檔案

"; }

直接使用記憶體流處理上傳檔案速度較快,歡迎測試反饋,若有優化建議也請不吝指教,共同進步。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved