[ASP.NET][C#]用NPOI dll 上傳Excel(.xls、.xlsx),讀取資料。為何FileUpload上傳檔案無作用(hasfile=false)。

  • 9070
  • 0
  • 2018-04-09

.

Info.xls

完成上傳XLS檔,用GridView呈現此檔案的內容:

Info.xlsx

完成上傳XLSX檔,用GridView呈現此檔案的內容:

首先,網站的Bin目錄裡要「加入參考」NOPI.dll,本範例的版本是2.0.1.0

Page1.aspx

※注意:FileUpload控制項不可以放在UpdatePanel裡面(如果有套用MasterPage,請注意是否有被UpdatePanel包住)!會無法上傳檔案喔(hasfile屬性總是為false)!

(參考:asp.net fileupload hasfile always false?  https://stackoverflow.com/a/10504360)

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Page1.aspx.cs" Inherits="Site1_Page1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:Label ID="Label7" runat="server" Text="上傳Excel檔Wafer ID Infomation:"></asp:Label>
        <asp:FileUpload ID="fuExcel" runat="server" Width="70%" />
        <asp:Button ID="btnUploadExcel" runat="server" Text="Excel上傳" ToolTip="Excel上傳" OnClick="btnUploadExcel_Click" />
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:GridView ID="GridView1" runat="server" UpdateMode="Conditional">
                </asp:GridView>
            </ContentTemplate>
            <Triggers>
                <asp:PostBackTrigger ControlID="btnUploadExcel"></asp:PostBackTrigger>
            </Triggers>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>

Page1.aspx.cs 

using System;
using System.Web.UI;
using NPOI.HSSF.UserModel;
using NPOI.XSSF.UserModel;
using System.Data;

public partial class Site1_Page1 : System.Web.UI.Page
{
    string gsFileServerDir = @"\\11.12.13.14\abc";    //FileServer UNC Path
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    //流程:1.上傳Excel檔。2. ASP.net讀Excel資料,然後Insert into Table。3.刪除上傳的Excel檔,避免硬碟空間不夠。
    protected void btnUploadExcel_Click(object sender, EventArgs e)
    {
        //NPOI 2.0起,要讀取舊的 Excel檔,副檔名 .xls  ( Excel 2003(含)以前的版本) 用 HSSF;
        //要讀取新的 Excel檔,副檔名 .xlsx  ( Excel 2007(含)以前的版本) 用 XSSF

        try
        {
            #region 上傳、存檔、匯入Excel檔
            string fileName = string.Empty;
            if (!System.IO.Directory.Exists(gsFileServerDir))
                System.IO.Directory.CreateDirectory(gsFileServerDir);

            if (fuExcel != null && fuExcel.HasFile)
            {
                fileName = fuExcel.FileName;
                string savePath = gsFileServerDir + fileName;
                //同檔名則覆蓋
                fuExcel.SaveAs(savePath);
                string extention = fileName.Split('.')[1];
                if (extention == "xlsx")
                    ImportXLSX();
                else
                    ImportXLS();
            }
            #endregion

        }
        catch (Exception err)
        {
            string sMsg = err.Message.Replace("\r\n", "\n").Replace("\n", "\\n");
            ScriptManager.RegisterStartupScript(this.Page, this.GetType(), this.ClientID, string.Format("alert('{0}');", sMsg), true);
        }
    }

    /// <summary>
    /// 匯入副檔名為.xls的Excel檔
    /// </summary>
    private void ImportXLS()
    {
        HSSFWorkbook workbook = null;
        HSSFSheet sheet = null;

        try
        {
            #region 讀Excel檔,逐行寫入DataTable
            workbook = new HSSFWorkbook(fuExcel.FileContent); //只能讀取 System.IO.Stream 
            //FileContent 屬性會取得指向要上載之檔案的 Stream 物件。這個屬性可以用於存取檔案的內容 (做為位元組)。 
            //   例如,您可以使用 FileContent 屬性傳回的 Stream 物件,將檔案的內容做為位元組進行讀取並將其以位元組陣列儲存。 
            //FileContent 屬性,型別:System.IO.Stream 

            sheet = (HSSFSheet)workbook.GetSheetAt(0);   //0表示:第一個 worksheet工作表
            DataTable dt = new DataTable();

            HSSFRow headerRow = (HSSFRow)sheet.GetRow(0);   //Excel 表頭列

            for (int colIdx = 0; colIdx <= headerRow.LastCellNum; colIdx++) //表頭列,共有幾個 "欄位"?(取得最後一欄的數字) 
            {
                if (headerRow.GetCell(colIdx) != null)
                    dt.Columns.Add(new DataColumn(headerRow.GetCell(colIdx).StringCellValue));
                    //欄位名有折行時,只取第一行的名稱做法是headerRow.GetCell(colIdx).StringCellValue.Replace("\n", ",").Split(',')[0]
            }

            //For迴圈的「啟始值」為1,表示不包含 Excel表頭列
            for (int rowIdx = 1; rowIdx <= sheet.LastRowNum; rowIdx++)   //每一列做迴圈
            {
                HSSFRow exlRow = (HSSFRow)sheet.GetRow(rowIdx); //不包含 Excel表頭列的 "其他資料列"
                DataRow newDataRow = dt.NewRow();

                for (int colIdx = exlRow.FirstCellNum; colIdx <= exlRow.LastCellNum; colIdx++)   //每一個欄位做迴圈
                {
                    if (exlRow.GetCell(colIdx) != null)
                        newDataRow[colIdx] = exlRow.GetCell(colIdx).ToString();    //每一個欄位,都加入同一列 DataRow
                }
                dt.Rows.Add(newDataRow);
            }

            GridView1.DataSource = dt;
            GridView1.DataBind();
            #endregion 讀Excel檔,逐行寫入DataTable
        }
        catch (Exception err)
        {
            throw err;
        }
        finally
        {
            //釋放 NPOI的資源
            workbook = null;
            sheet = null;
        }
    }

    /// <summary>
    /// 匯入副檔名為.xlsx的Excel檔
    /// </summary>
    private void ImportXLSX()
    {
        XSSFWorkbook workbook = null;
        XSSFSheet sheet = null;

        try
        {
            #region 讀Excel檔,逐行寫入DataTable
            workbook = new XSSFWorkbook(fuExcel.FileContent); //只能讀取 System.IO.Stream 
            //FileContent 屬性會取得指向要上載之檔案的 Stream 物件。這個屬性可以用於存取檔案的內容 (做為位元組)。 
            //   例如,您可以使用 FileContent 屬性傳回的 Stream 物件,將檔案的內容做為位元組進行讀取並將其以位元組陣列儲存。 
            //FileContent 屬性,型別:System.IO.Stream 

            sheet = (XSSFSheet)workbook.GetSheetAt(0);   //0表示:第一個 worksheet工作表
            DataTable dt = new DataTable();

            XSSFRow headerRow = (XSSFRow)sheet.GetRow(0);   //Excel 表頭列
            

            for (int colIdx = 0; colIdx <= headerRow.LastCellNum; colIdx++) //表頭列,共有幾個 "欄位"?(取得最後一欄的數字) 
            {
                if (headerRow.GetCell(colIdx) != null)
                    dt.Columns.Add(new DataColumn(headerRow.GetCell(colIdx).StringCellValue));
                    //欄位名有折行時,只取第一行的名稱做法是headerRow.GetCell(colIdx).StringCellValue.Replace("\n", ",").Split(',')[0]
            }

            //For迴圈的「啟始值」為1,表示不包含 Excel表頭列
            for (int rowIdx = 1; rowIdx <= sheet.LastRowNum; rowIdx++)   //每一列做迴圈
            {
                XSSFRow exlRow = (XSSFRow)sheet.GetRow(rowIdx); //不包含 Excel表頭列的 "其他資料列"
                DataRow newDataRow = dt.NewRow();

                for (int colIdx = exlRow.FirstCellNum; colIdx <= exlRow.LastCellNum; colIdx++)   //每一個欄位做迴圈
                {
                    if (exlRow.GetCell(colIdx) != null)
                        newDataRow[colIdx] = exlRow.GetCell(colIdx).ToString();    //每一個欄位,都加入同一列 DataRow
                }
                dt.Rows.Add(newDataRow);
            }

            GridView1.DataSource = dt;
            GridView1.DataBind();
            #endregion 讀Excel檔,逐行寫入DataTable
        }
        catch (Exception err)
        {

            throw err;
        }
        finally
        {
            //釋放 NPOI的資源
            workbook = null;
            sheet = null;
        }
    }

}

下載最新版 .DLL檔、Example,請至NPOI網站:  https://npoi.codeplex.com/releases/view/115353

名詞說明:
HSSF - 提供讀寫Microsoft Excel XLS格式檔案的功能。
XSSF - 提供讀寫Microsoft Excel OOXML XLSX格式檔案的功能。
HWPF - 提供讀寫Microsoft Word DOC格式檔案的功能。
HSLF - 提供讀寫Microsoft PowerPoint格式檔案的功能。
HDGF - 提供讀Microsoft Visio格式檔案的功能。
HPBF - 提供讀Microsoft Publisher格式檔案的功能。
HSMF - 提供讀Microsoft Outlook格式檔案的功能。 

有關POI的說明可參考:
http://en.wikipedia.org/wiki/Apache_POI

來源:

https://dotblogs.com.tw/mis2000lab/archive/2012/06/19/asp_net_read_excel_and_export_20120619.aspx

http://einboch.pixnet.net/blog/post/274497938-%E4%BD%BF%E7%94%A8npoi%E7%94%A2%E7%94%9Fexcel%E6%AA%94%E6%A1%88

延伸閱讀:

http://ericitworld.blogspot.tw/2013/09/npoiexcel.html

https://dotblogs.com.tw/mis2000lab/2014/11/13/npoi_20_fileupload

https://dotblogs.com.tw/mis2000lab/2015/06/29/npoi_2131_sample_export_to_excel

http://lhzyaminabe.blogspot.tw/2015/10/nugetnpoi.html

http://einboch.pixnet.net/blog/post/274497938-%E4%BD%BF%E7%94%A8npoi%E7%94%A2%E7%94%9Fexcel%E6%AA%94%E6%A1%88

用Office Excel:Microsoft.Office.Interop.Excel命名空間  https://dotblogs.com.tw/yc421206/2009/01/10/6727

用Office Excel的範例:https://dotblogs.com.tw/shadow/archive/2011/05/02/24045.aspx

用LinqToExcel:讀取 Excel 你還在用 NPOI 嗎?快來試試 LinqToExcel  http://demo.tc/post/639

如何讓GridView查詢資料後按匯出鈕直接匯出excel檔  https://www.blueshop.com.tw/board/FUM20041006161839LRJ/BRD20150724160525I25.html