2020年4月20日 星期一

[研究][C#][ASP.NET][WebForm] 用 ClosedXML 0.95.0 匯入 Excel (.xlsx) 檔案

[研究][C#][ASP.NET][WebForm] 用 ClosedXML 0.95.0 匯入 Excel (.xlsx) 檔案

2020-04-20
2020-04-24 修訂

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="GridViewImportXlsxByClosedXML.Default" %>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:FileUpload ID="FileUpload1" runat="server" /><br />
        <asp:Button ID="Button_Import_by_ClosedXML" runat="server" Text="匯入" OnClick="Button_Import_by_ClosedXML_Click" /><br />
            <asp:Label ID="Label_ExportImportMSG" runat="server"></asp:Label><br />
        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:TestDBConnectionString %>" 
            SelectCommand="SELECT * FROM [MyTable]"></asp:SqlDataSource>
        <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" 
            DataKeyNames="SN" DataSourceID="SqlDataSource1">
            <Columns>
                <asp:BoundField DataField="SN" HeaderText="SN" InsertVisible="False" ReadOnly="True" SortExpression="SN" />
                <asp:BoundField DataField="myID" HeaderText="myID" SortExpression="myID" />
                <asp:BoundField DataField="myName" HeaderText="myName" SortExpression="myName" />
                <asp:BoundField DataField="purchaseDate" HeaderText="purchaseDate" SortExpression="purchaseDate" />
            </Columns>
        </asp:GridView>
    </form>
</body>
</html>



注意,下面連線字串名稱 TestDBConnectionString 要換成自己的。否則會出現【並未將物件參考設定為物件的執行個體。】錯誤。資料表 MyTable 和欄位名稱也要換自己的。

如果出現錯誤【字串或二進位資料會被截斷。】,可以一次1000筆太長,減少些。
如果改成1筆也這樣,表示欄位長度不夠放入資料,請改 DB Schema。

.xlsx 檔案第一橫列的【排序與篩選】功能必須關閉,存檔,再匯入,否則匯入會失敗。
否則/ using (XLWorkbook workBook = new XLWorkbook(fileName)) 開檔案會失敗。

Default.aspx.cs


using ClosedXML.Excel;
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Text.RegularExpressions;
using System.Web.Configuration;

namespace GridViewImportXlsxByClosedXML
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button_Import_by_ClosedXML_Click(object sender, EventArgs e)
        {
            Label_ExportImportMSG.Text = "";
            int lineNo = 2;
            string queryString = @"truncate  Table MyTable; 
                DBCC CHECKIDENT('MyTable', RESEED, 1); ";
            bool importSuccess = true;
            string myID = "";
            string myName = "";
            string purchaseDate = "";

            try
            {
                if (FileUpload1.HasFile)
                {
                    string fd = (string)ConfigurationManager.AppSettings["InformationSystemFiles"] + "\\";
                    if (!System.IO.Directory.Exists(fd))
                    {
                        System.IO.Directory.CreateDirectory(fd);
                    }
                    string extFileName = System.IO.Path.GetExtension(FileUpload1.FileName).ToLower();
                    // ClosedXML 0.94.2
                    // Extension 'csv' is not supported. Supported extensions are '.xlsx', '.xslm', '.xltx' and '.xltm'.
                    if (!(extFileName == ".xlsx"))
                    {
                        Label_ExportImportMSG.Text = "<font color=red>請上傳副檔名.xlsx檔案</font>";
                        //ScriptManager.RegisterStartupScript(this, GetType(), "Popup1", "erroralert('" + "請上傳副檔名.xlsx檔案!" + "');", true);
                        return;
                    }
                    string mainFileName = Path.GetFileNameWithoutExtension(FileUpload1.FileName);
                    string fileName = @"D:\\Production\\TempImageFiles\\" + mainFileName + "-" + DateTime.Now.ToString("-yyyy-MM-dd HH-mm-ss") + extFileName;
                    FileUpload1.SaveAs(fileName);

                    var dt = new DataTable();
                    using (XLWorkbook workBook = new XLWorkbook(fileName))
                    {
                        var workSheet = workBook.Worksheet("工作表1");
                        var firstCell = workSheet.FirstCellUsed();
                        var lastCell = workSheet.LastCellUsed();
                        dt = workSheet.Range(firstCell.Address, lastCell.Address).AsTable().AsNativeDataTable();
                    }

                    int i = 0;
                    foreach (DataRow item in dt.Rows)
                    {
                        myID = item[0].ToString().Trim();
                        myName = item[1].ToString().Trim();

                        // Excel 儲存格格式若為【日期】,「2020/3/1」回傳「2020/3/1 上午 00:00:00」
                        // Excel 儲存格格式若為【文字】,「2020/3/1」回傳「2020/3/1」
                        // 插入 SQL Server 會出現【從字元字串轉換成日期及/或時間時,轉換失敗。】錯誤,要想辦拿拿掉【上午】兩字
                        purchaseDate = item[2].ToString().Trim();

                        // 檢查「名稱」
                        if (string.IsNullOrEmpty(myName))
                        {
                            Label_ExportImportMSG.Text = "<font color=red>第 " + lineNo.ToString() + "行,「名稱」不可空</font>";
                            return;
                        }
                        if (myName.Length > 50)
                        {
                            Label_ExportImportMSG.Text = "<font color=red>第 " + lineNo.ToString() + "行,「名稱」您輸入為「" + myName + "」,長度超過50個字(全半形都算1個)。</font>";
                            return;
                        }
                        //----
                        // 檢查「購置日期」

                        // 檢查「日期」格式 YYYY/MM/DD,但 YYYY/M/D、YYYY/MM/D、YYYY/M/DD 不行
                        //string regularExpressions = @"^([2][0]\d{2}\/([0]\d|[1][0-2])\/([0-2]\d|[3][0-1]))$|^([2][0]\d{2}\/([0]\d|[1][0-2])\/([0-2]\d|[3][0-1]))$";
                        //(19 | 20)[0 - 9]{ 2}[- /.] (0[1-9]|1[012])[- /.] (0[1-9]|[12] [0-9]|3[01])

                        // YYYY/MM/DD、YYYY/MM/D、YYYY/M/DD、YYYY/M/D 都可以,但 9999/9/99 會過
                        // 「2020/3/1 上午 12:00:00」實際測試也會過 ( Why ?) DateTime.TryParse 得到相同值;
                        string regularExpressions = @"^(\d{4}(?:/\d{1,2}){2})";
                        Match m = Regex.Match(purchaseDate, regularExpressions);

                        if (m.Success)
                        {
                            DateTime temp;
                            if (DateTime.TryParse(purchaseDate, out temp))
                            {
                                //PurchaseDate=temp.ToString("yyyy/MM/dd HH:mm:ss");
                                // Excel 儲存格格式若為【日期】,ClosedXML 對「2020/3/1」回傳「2020/3/1 上午 00:00:00」
                                // Excel 儲存格格式若為【文字】,ClosedXML 對「2020/3/1」回傳「2020/3/1」
                                // 插入 SQL Server 會出現【從字元字串轉換成日期及/或時間時,轉換失敗。】錯誤,要想辦拿拿掉【上午】兩字
                                purchaseDate = temp.ToString("yyyy/MM/dd");
                            }
                            else
                            {
                                Label_ExportImportMSG.Text = "<font color=red>第 " + lineNo.ToString() + "行,「購置日期」您輸入為「" + purchaseDate + "」,日期不合理。</font>";
                                return;
                            }
                            //return true;
                        }
                        else
                        {
                            Label_ExportImportMSG.Text = "<font color=red>第 " + lineNo.ToString() + "行,「購置日期」您輸入為「" + purchaseDate + "」,格式不符 YYYY/MM/DD 或 YYYY/MM/D 或 YYYY/M/DD 或 YYYY/MM/DD。</font>";
                            return;
                        }
                        //----
                        queryString = queryString + @"
INSERT INTO [dbo].[MyTable]
           ([MyID]
           ,[MyName]
           ,[PurchaseDate]
            )
     VALUES
           ('" + myID + "',N'" +
           myName + "',N'" +
           purchaseDate + "'); ";

                        lineNo = lineNo + 1;
                    } // foreach
                    using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TestDBConnectionString"].ConnectionString))
                    {
                        SqlCommand command = new SqlCommand(queryString, connection);
                        command.Connection.Open();
                        command.ExecuteNonQuery();

                        GridView1.DataSourceID = "";
                        GridView1.DataSourceID = "SqlDataSource1";
                        GridView1.DataBind();
                        Label_ExportImportMSG.ForeColor = System.Drawing.Color.Green;
                        Label_ExportImportMSG.Text = "匯入成功!";
                    } // using
                }

                else
                {
                    Label_ExportImportMSG.Text = "<font color=red>請選擇.xlsx檔案</font>";
                    return;
                }//if (FileUpload1.HasFile)
            }
            catch (Exception ex)
            {
                if (ex != null)
                {
                    Label_ExportImportMSG.Text = ex.Message.ToString();
                    if (Label_ExportImportMSG.Text.Contains("找不到資料行"))
                    {
                        Label_ExportImportMSG.Text = Label_ExportImportMSG.Text + "請不要擅自刪除欄位,或自創.xlsx內容格式。";
                    }
                }
                else
                {
                    Label_ExportImportMSG.Text = "匯入失敗!";
                    Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('匯入失敗!');</script>");
                }
                Label_ExportImportMSG.ForeColor = System.Drawing.Color.Red;
                importSuccess = false;
            }
        }
    }
}

(完)

沒有留言:

張貼留言