顯示具有 OpenXML SDK 標籤的文章。 顯示所有文章
顯示具有 OpenXML SDK 標籤的文章。 顯示所有文章

2021年2月18日 星期四

[研究][ASP.NET]使用 OpenXML 2.12.2 匯出、寫入 .xlsx

[研究][ASP.NET]使用 OpenXML 2.12.2 匯出、寫入 .xlsx

2021-02-18

環境:Visual Studio 2019 + ASP.NET + WebForm + C# + NuGet 安裝 OpenXML 2.12.2


packages.conf
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="DocumentFormat.OpenXml" version="2.12.2" targetFramework="net472" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="2.0.1" targetFramework="net472" />
</packages>

Web.Config
<?xml version="1.0" encoding="utf-8"?>

<!--
  如需如何設定 ASP.NET 應用程式的詳細資訊,請前往
  https://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <connectionStrings>
    <add name="TestDBConnectionString" connectionString="Data Source=.;Initial Catalog=TestDB;User ID=sa;Password=P@ssw0rd"
      providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.7.2"/>
    <httpRuntime targetFramework="4.7.2"/>
  </system.web>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
    </compilers>
  </system.codedom>
	<appSettings>
		<add key="TempFolder" value="D:\WWW\Temp" />
	</appSettings>
</configuration>

Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ExportXlsxByOpenXMLSDKTest.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">
        <div>
            <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
                ConnectionString="<%$ ConnectionStrings:TestDBConnectionString %>" 
                SelectCommand="SELECT * FROM [Table1]"></asp:SqlDataSource>
            <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" 
                AutoGenerateColumns="False" DataKeyNames="id" DataSourceID="SqlDataSource1">
                <Columns>
                    <asp:BoundField DataField="id" HeaderText="id" InsertVisible="False" ReadOnly="True" SortExpression="id" />
                    <asp:BoundField DataField="FieldText" HeaderText="FieldText" SortExpression="FieldText" />
                    <asp:BoundField DataField="FieldDateTime" HeaderText="FieldDateTime" SortExpression="FieldDateTime" />
                    <asp:BoundField DataField="FieldInt" HeaderText="FieldInt" SortExpression="FieldInt" />
                    <asp:CheckBoxField DataField="FieldBit" HeaderText="FieldBit" SortExpression="FieldBit" />
                </Columns>
            </asp:GridView>
            <asp:Button ID="Button_Export_Xlsx_By_OpenXML" runat="server" 
                OnClick="Button_Export_Xlsx_By_OpenXML_Click" Text="匯出(.xlsx)" /><br />
            <asp:Label ID="Label_MSG1" runat="server"></asp:Label>
        </div>
    </form>
</body>
</html>


Default.aspx.cs
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Configuration;
using System.Web.UI;
using System.Web.UI.WebControls;

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

        }
        protected void Button_Export_Xlsx_By_OpenXML_Click(object sender, EventArgs e)
        {
            /*
            Open XML SDK 2.5 for Microsoft Office
            https://www.microsoft.com/en-us/download/details.aspx?id=30425

            微軟官方下載只提供到 2.5 版,NuGet 才能下載到更新版。
            另外 OpenXML 在不同版本時,API function method 用法不完全相同。

            Welcome to the Open XML SDK 2.5 for Office
            2017/11/01
            https://docs.microsoft.com/zh-tw/office/open-xml/open-xml-sdk

            DocumentFormat.OpenXml 2.7.2
            https://docs.microsoft.com/zh-tw/dotnet/api/documentformat.openxml.spreadsheet?view=openxml-2.7.2

            DocumentFormat.OpenXml 2.8.1
            https://docs.microsoft.com/zh-tw/dotnet/api/documentformat.openxml.spreadsheet?view=openxml-2.8.1

            DocumentFormat.OpenXml 2.12.2
            https://docs.microsoft.com/zh-tw/dotnet/api/documentformat.openxml.spreadsheet?view=openxml-2.12.2

            Import
            https://docs.microsoft.com/en-us/office/open-xml/how-to-parse-and-read-a-large-spreadsheet

            Export
            https://docs.microsoft.com/en-us/office/open-xml/how-to-create-a-spreadsheet-document-by-providing-a-file-name

            Insert text into a cell in a spreadsheet document(Open XML SDK)
            https://docs.microsoft.com/zh-tw/office/open-xml/how-to-insert-text-into-a-cell-in-a-spreadsheet
            
             */

            string mainFileName = "匯出檔案名稱";
            string fd = (string)ConfigurationManager.AppSettings["TempFolder"] + @"\";
            if (!System.IO.Directory.Exists(fd))
            {
                System.IO.Directory.CreateDirectory(fd);
            }
            string dateTimeString = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-fff");
            // 若檔案名稱有中文字或特殊符號,Response.AddHeader() 輸出檔案名稱要編碼
            string outFileName = HttpUtility.UrlEncode(
                mainFileName, System.Text.Encoding.UTF8) + "-" +
                dateTimeString + ".xlsx";

            // XLWorkbook.SaveAs() 輸出檔案名稱不要用 HttpUtility.UrlEncode 編碼
            // Response.TransmitFile() 輸出檔案名稱不要用 HttpUtility.UrlEncode 編碼
            string dirFileName = fd + mainFileName + "-" +
                dateTimeString + ".xlsx";
            try
            {
                Response.Clear();
                Response.Buffer = true;
                Response.Charset = "";

                #region Export ODS

                // [EXCEL] Excel打開是亂碼?快速找回資料的最好方法!
                // http://blog.e-happy.com.tw/excel-excel%E6%89%93%E9%96%8B%E6%98%AF%E4%BA%82%E7%A2%BC%EF%BC%9F%E5%BF%AB%E9%80%9F%E6%89%BE%E5%9B%9E%E8%B3%87%E6%96%99%E7%9A%84%E6%9C%80%E5%A5%BD%E6%96%B9%E6%B3%95%EF%BC%81/

                // Excel開啟CSV時的中文編碼問題補遺
                //https://blog.darkthread.net/blog/csv-encoding-again/

                //Response.ContentType = "application/vnd.oasis.opendocument.spreadsheet";    // ODF/.ods
                //Response.AddHeader("content-disposition", "attachment;filename=" + outFileName);
                using (MemoryStream myMemoryStream = new MemoryStream())
                {
                    //StreamWriter odsFileStreamWriter = new StreamWriter(MyMemoryStream);
                    //StreamReader odsFileStreamReader = new StreamReader(new MemoryStream());
                    string dataText = "";

                    SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(myMemoryStream, SpreadsheetDocumentType.Workbook, true);
                    WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
                    workbookpart.Workbook = new Workbook();
                    // Add a WorksheetPart to the WorkbookPart.
                    WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
                    worksheetPart.Worksheet = new Worksheet(new SheetData());

                    // Add Sheets to the Workbook.
                    Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild(new Sheets());
                    // Append a new worksheet and associate it with the workbook.
                    Sheet sheet = new Sheet() { Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "工作表1" };
                    sheets.Append(sheet);
                    // Get the sheetData cell table.
                    SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
                    // Add a column row to the cell table.
                    Row colrow;
                    colrow = new Row() { RowIndex = 1 };
                    sheetData.Append(colrow);

                    // 定義欄位名稱列
                    string[] columnNameArray = { "id", "FieldText", "FieldDateTime", "FieldInt", "FieldBit" };
                    // Column number must be between 1 and 16384
                    for (int i = 0; i < columnNameArray.Count(); i++)
                    {
                        Cell CReceiptID = new Cell();
                        CReceiptID.CellValue = new CellValue(columnNameArray[i]);
                        CReceiptID.DataType = new EnumValue<CellValues>(CellValues.String);
                        colrow.InsertAt(CReceiptID, i);
                        //string debugValue = sheetData.Cell(i,j).GetString();
                    }

                    // 讀取資料,資料寫入「工作表1」
                    string queryString = @"
--DECLARE  @FieldText nvarchar(50)
--SET @FieldText=N'abc'

SELECT * FROM [TestDB].[dbo].[Table1]
";

                    using (SqlConnection connection = new SqlConnection(
                        WebConfigurationManager.ConnectionStrings["TestDBConnectionString"].ConnectionString))
                    {
                        SqlCommand command = new SqlCommand(queryString, connection);
                        //command.Parameters.Clear();
                        //command.Parameters.AddWithValue("@FieldText", queryFieldText);
                        connection.Open();
                        SqlDataReader reader = command.ExecuteReader();

                        // Add rows to the cell table
                        UInt32Value DataIndex = new UInt32Value();
                        DataIndex.Value = 2;     // 1 是標題列
                        //int rowIndex = 2;   // 1 是標題列
                        while (reader.Read())
                        {
                            Row row;
                            row = new Row() { RowIndex = DataIndex.Value };
                            sheetData.Append(row);

                            for (int i = 0; i < reader.FieldCount; i++)
                            {
                                //reader[i]的 i 要從 0 開始
                                dataText = reader[i].ToString();

                                // 規則運算式語言 - 快速參考 | Microsoft Docs
                                // https://docs.microsoft.com/zh-tw/dotnet/standard/base-types/regular-expression-language-quick-reference

                                // 換掉特殊字元 (自己評估)
                                dataText = dataText.Replace("\r", "").Replace("\n", "").Replace("\t", "").Replace(",", ",").Replace("'", "′").Replace(@"""", "”");
                                dataText = dataText.Replace("\a", "").Replace("\b", "").Replace("\t", "").Replace("\v", "").Replace("\f", "").Replace("\\", "");

                                Cell CReceiptID = new Cell();
                                CReceiptID.CellValue = new CellValue(dataText);
                                CReceiptID.DataType = new EnumValue<CellValues>(CellValues.String);
                                row.InsertAt(CReceiptID, i);
                            }
                            DataIndex.Value++;
                        }

                        Response.Clear();
                        Response.Buffer = true;
                        Response.Charset = "";
                        //Response.ContentEncoding = Encoding.GetEncoding(950);   //950就是所謂的BIG5
                        //Response.AddHeader("Content-Disposition", "attachment;filename=\"" +
                        //    HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8) + "-" +
                        //    DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx");
                        Response.AddHeader("Content-Disposition", "attachment;filename=\"" + outFileName);
                        //'Excel 2003 : "application/vnd.ms-excel"
                        //'Excel 2007 : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

                        //Extension       MIME Type
                        //.xlsx               application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
                        //.xltx                application/vnd.openxmlformats-officedocument.spreadsheetml.template
                        //.potx               application/vnd.openxmlformats-officedocument.presentationml.template
                        //.ppsx              application/vnd.openxmlformats-officedocument.presentationml.slideshow
                        //.pptx               application/vnd.openxmlformats-officedocument.presentationml.presentation
                        //.sldx               application/vnd.openxmlformats-officedocument.presentationml.slide
                        //.docx              application/vnd.openxmlformats-officedocument.wordprocessingml.document
                        //.dotx               application/vnd.openxmlformats-officedocument.wordprocessingml.template
                        //.xlam              application/vnd.ms-excel.addin.macroEnabled.12
                        //.xlsb               application/vnd.ms-excel.sheet.binary.macroEnabled.12

                        //Response.ContentType = "application/ms-excel";
                        Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

                        //Response.TransmitFile(@"C:\Program Files (x86)\IIS Express\Export.xlsx");
                        //dirFileName = dirFileName.Replace('\\', '/');   //轉換 Windows, Linux 不同路徑斜線
                        //dirFileName = dirFileName.Replace("/", "\\");  // 轉換斜線 / 成 \  ,因 \ 是特殊符號,要以 \\ 表示

                        // 方法1: 直接輸出
                        worksheetPart.Worksheet.Save();
                        workbookpart.Workbook.Save();
                        spreadsheetDocument.SaveAs(dirFileName);    // 方法2: 寫入檔案再輸出
                        spreadsheetDocument.Close();

                        myMemoryStream.WriteTo(Response.OutputStream);
                        Response.Flush();

                        // // 方法2: 寫入檔案再輸出
                        //Response.TransmitFile(dirFileName);   // 把存檔輸出

                        // 3.輸出結束
                        Response.End();

                        Label_MSG1.ForeColor = System.Drawing.Color.Green;
                        Label_MSG1.Text = "匯出成功。";
                        // 上面 Response 輸出檔案,所以下面 JavaScript alert 是不會跳出的
                        //Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('匯出成功。');</script>");
                    }
                }
                #endregion Export ODS
            }
            catch (Exception ex)
            {
                Label_MSG1.ForeColor = System.Drawing.Color.Red;
                string exMsg = "不明錯誤。";
                if (ex != null)
                {
                    exMsg = ex.ToString();
                }
                Label_MSG1.Text = exMsg;
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('匯出失敗。');</script>");
                // Exception Message 內容可能導致 JavaScript alert 無法顯示,所以下面這行可能無法跳出對話盒視窗。
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('" + exMsg + "');</script>");
            }
        }
        // ----------
    }
}

不過根據以往經驗,元件直接產生的 .xlsx,和用 Excel 建立的 .xlsx,實際的檔案骨架 schema 好像沒有 100% 相同,前者用某些元件或版本匯入可能正常或會出錯,但前者用 Microsoft Excel 軟體直接開啟正常。

或可考慮先用 Excel 2016 或 Excel 2019 做好一個沒填寫內容的 活頁簿 (Workbook) 和 工作表1 (Worksheet),複製後 (避免多人同開開起讀寫),再拿來寫入、關閉、匯出。

(完)

2021年2月4日 星期四

[研究][ASP.NET]使用 OpenXML SDK 2.12.1 讀取匯入 .xlsx 到資料庫

[研究][ASP.NET]使用 DocumentFormat.OpenXml 2.12.1 讀取匯入 .xlsx 到資料庫

2021-02-04

Microsoft OpenXML SDK 安裝後,packages.conf 中元件名稱是 DocumentFormat.OpenXml。

環境:Visual Studio 2019 + ASP.NET + WebForm + C# + NuGet 安裝 OpenXML SDK 2.12.1

Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ImportXlsxByOpenXMLSDKTest.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">
        <div>
            <asp:FileUpload ID="FileUpload1" runat="server" /><br />
            <asp:Button ID="Button_Import_xlsx_by_OpenXMLSDK_DocumentFormatOpenXml" runat="server" Text="匯入(.xlsx)" OnClick="Button_Import_xlsx_by_OpenXMLSDK_DocumentFormatOpenXml_Click" /><br />
            <br />
            <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:TestDBConnectionString %>" SelectCommand="SELECT * FROM [Table1]"></asp:SqlDataSource>
            <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="id" DataSourceID="SqlDataSource1">
                <Columns>
                    <asp:BoundField DataField="id" HeaderText="id" InsertVisible="False" ReadOnly="True" SortExpression="id" />
                    <asp:BoundField DataField="FieldText" HeaderText="FieldText" SortExpression="FieldText" />
                    <asp:BoundField DataField="FieldDateTime" HeaderText="FieldDateTime" SortExpression="FieldDateTime" />
                    <asp:BoundField DataField="FieldInt" HeaderText="FieldInt" SortExpression="FieldInt" />
                    <asp:CheckBoxField DataField="FieldBit" HeaderText="FieldBit" SortExpression="FieldBit" />
                </Columns>
            </asp:GridView>
            <asp:Label ID="Label_ExportImportMSG" runat="server"></asp:Label><br />
            <asp:Label ID="Label_MSG1" runat="server"></asp:Label>
        </div>
    </form>
</body>
</html>


Default.aspx.cs

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using System.Web.UI;
using System.Web.UI.WebControls;

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

        }

        protected void Button_Import_xlsx_by_OpenXMLSDK_DocumentFormatOpenXml_Click(object sender, EventArgs e)
        {
            // Microsoft OpenXML SDK 安裝後,packages.conf 中元件名稱是 DocumentFormat.OpenXml
            // https://docs.microsoft.com/en-us/office/open-xml/how-to-parse-and-read-a-large-spreadsheet

            Label_MSG1.Text = "";
            Label_ExportImportMSG.Text = "";
            int lineNo = 0;
            int lineCount = 0;
            int successCount = 0;
            string queryString = "";
            string errMsg = "";
            int rowCount = 0;
            int columnCount = 0;


            if (!FileUpload1.HasFile)
            {
                Label_ExportImportMSG.Text = "<font color=red>請選擇.xlsx檔案</font>";
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('請選擇.xlsx檔案。');</script>");
                return;
            }
            else
            {
                //string fd = (string)ConfigurationManager.AppSettings["TempFolder"] + "\\";
                string fd = @"C:\Temp";
                if (!System.IO.Directory.Exists(fd))
                {
                    System.IO.Directory.CreateDirectory(fd);
                }
                string ext = System.IO.Path.GetExtension(FileUpload1.FileName).ToLower();
                if (!(ext == ".xlsx"))
                {
                    Label_ExportImportMSG.Text = "<font color=red>請上傳副檔名.xlsx檔案</font>";
                    ScriptManager.RegisterStartupScript(this, GetType(), "Popup1", "erroralert('" + "請上傳副檔名.xlsx檔案!" + "');", true);
                    return;
                }
                string fileName = fd + FileUpload1.FileName;
                FileUpload1.SaveAs(fileName);

                string mainFileName = Path.GetFileNameWithoutExtension(FileUpload1.FileName);
                string openFilename = fd + mainFileName + "-匯入結果" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-fff") + ".xlsx";
                FileUpload1.SaveAs(openFilename);

                string fieldText = "";
                string fieldDateTime = "";
                string fieldInt = "";
                string fieldBit = "";

                // 清空
                //queryString = @"DELETE FROM [dbo].[Table1] WHERE id=@id; ";
                queryString = @"DELETE FROM [dbo].[Table1]; ";
                using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TestDBConnectionString"].ConnectionString))
                {
                    SqlCommand command = new SqlCommand(queryString, connection);
                    connection.Open();
                    command.ExecuteNonQuery();
                }

                // 讀資料
                using (DocumentFormat.OpenXml.Packaging.SpreadsheetDocument spreadsheetDocument =
                    DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(openFilename, false))
                {
                    WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
                    WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
                    SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();
                    //string text;

                    lineCount = sheetData.Elements<Row>().Count();
                    rowCount = sheetData.Elements<Row>().Count();
                    // 錯誤
                    //int columnCount2 = sheetData.Elements<Columns>().Count();
                    //int columnCount3 = sheetData.Elements<ColumnFields>().Count();
                    //int columnCount4 = sheetData.Elements<ColumnItems>().Count();
                    //int columnCount5 = sheetData.Elements<Cell>().Count();
                    foreach (Row r in sheetData.Elements<Row>())
                    {
                        columnCount = r.Descendants<Cell>().Count();

                        //foreach (Cell c in r.Elements<Cell>())
                        //{
                        //    text = c.CellValue.Text;
                        //    //Console.Write(text + " ");
                        //}

                        // lineNo 初始值0,lineNo=1,第1列標題,不讀取
                        lineNo++;
                        if (lineNo != 1)
                        {
                            // 讀文字
                            // CellValues.SharedString
                            // Cell cell = (Cell)r.ChildElements.GetItem(0);
                            // cell.DataType = CellValues.SharedString
                            
                            // 似乎 OpenXML 會跳過空橫列不理會,讀取下一橫列內容
                            fieldText = getOpenXMLSDKCellValue(workbookPart, (Cell)r.ChildElements.GetItem(0));
                            
                            if (fieldText != "")
                            {
                                // CellValues.Date
                                fieldDateTime = getOpenXMLSDKCellValue(workbookPart, (Cell)r.ChildElements.GetItem(1));
                                DateTime.TryParse(fieldDateTime, out DateTime fieldDateTime2);

                                // 數值讀法和文字不同,就算「儲存格格式」設定為「文字」,輸入數字,仍可正常讀取
                                // CellValues.Number
                                fieldInt = ((Cell)r.ChildElements.GetItem(2)).InnerText;

                                // Excel 填 1 或 0 表示 True 或 False
                                fieldBit = ((Cell)r.ChildElements.GetItem(3)).InnerText;

                                queryString = @"
INSERT INTO [dbo].[Table1]
           ([FieldText]
           ,[FieldDateTime]
           ,[FieldInt]
           ,[FieldBit])
     VALUES
           (N'" + fieldText + "'" +
           ",'" + fieldDateTime2.ToString("yyyy/MM/dd HH:mm:ss.fff") + "'" +
           ",'" + fieldInt + "'" +
           ",'" + fieldBit + "'); ";
                                using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TestDBConnectionString"].ConnectionString))
                                {
                                    SqlCommand command = new SqlCommand(queryString, connection);
                                    //command.Parameters.Clear();
                                    //command.Parameters.AddWithValue("@unit_oid", DropDownList_Jiguan.SelectedValue);
                                    connection.Open();
                                    try
                                    {
                                        command.ExecuteNonQuery();
                                        successCount++;
                                    }
                                    catch (Exception ex)
                                    {
                                        errMsg = "不明錯誤。";
                                        if (ex != null)
                                            errMsg = ex.Message.ToString();

                                        errMsg = "#1匯入.xlsx 共 " + rowCount + " 列 " + columnCount + " 行 (若沒看到,可能填寫了不可見字元)," +
                                            "第" + lineNo + "筆(Excel 第" + (lineNo + 1) + "列) 匯入失敗。\\n" + errMsg;
                                        Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('" + errMsg + "'');</script>");
                                        return;
                                    }
                                } // using (SqlConnection connection
                            } // if
                            else
                            {
                                // fieldText == ""
                                errMsg = "#2匯入.xlsx 共 " + rowCount + " 列 " + columnCount + " 行 (若沒看到,可能填寫了不可見字元)," +
                                    "第" + lineNo + "筆(Excel 第" + (lineNo + 1) + "列) 第1欄為空的,中斷匯入。\\n若資料已全部匯入,可忽略此問題。";
                                Page.ClientScript.RegisterStartupScript(Page.GetType(), "message", "<script language='javascript' defer>alert('" + errMsg + "');</script>");
                                return;
                            } // if
                        } // if (lineNo != 1)
                    } // foreach (Row r in sheetData.Elements<Row>())
                } // using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(openFilename, false))

                //string url = "/List.aspx?Ref1=" + Request.QueryString["Ref1"].ToString() + "&Ref2=" + Request.QueryString["Ref2"].ToString() + "&Ref3=" + Request.QueryString["Ref3"].ToString();
                string url = "#";
                errMsg = "#3匯入.xlsx 共 " + rowCount + " 列 " + columnCount + " 行 (若沒看到,可能填寫了不可見字元)," +
                                    "成功匯入" + successCount + "筆資料。\\n" +
                                    "按【確定】轉往列表畫面。";
                
                ClientScript.RegisterStartupScript(GetType(), "message", "<script>alert('" + errMsg + "');location.href='" + url + "';</script>");
            } //if (FileUpload1.HasFile)

            GridView1.DataBind();
        }
        protected string getOpenXMLSDKCellValue(WorkbookPart workbookPart, Cell currentcell)
        {
            string currentcellvalue = "";
            if (currentcell.DataType != null)
            {
                // Excel「儲存格格式」為「通用格式」,輸入非數字、非日期文字,DataType == CellValues.SharedString
                // Excel「儲存格格式」為「通用格式」,輸入日期,DataType == CellValues.SharedString
                if (currentcell.DataType == CellValues.SharedString)
                {
                    int id = -1;

                    if (Int32.TryParse(currentcell.InnerText, out id))
                    {
                        SharedStringItem item = workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(id);

                        if (item.Text != null)
                        {
                            //code to take the string value  
                            currentcellvalue = item.Text.Text;
                        }
                        else if (item.InnerText != null)
                        {
                            currentcellvalue = item.InnerText;
                        }
                        else if (item.InnerXml != null)
                        {
                            currentcellvalue = item.InnerXml;
                        }
                    }
                }
                //if (currentcell.DataType == CellValues.Number)
                //{
                //    currentcellvalue = currentcell.InnerText;
                //}
                //if (currentcell.DataType == CellValues.Date)
                //{
                //    //if (DateTime.TryParse(currentcell.InnerText, out DateTime currentcellDateTime))
                //    if (double.TryParse(currentcell.InnerText, out double currentcellDateTime))
                //    {
                //        //return System.DateTime.FromOADate(currentcellDateTime);
                //        return System.DateTime.FromOADate(currentcellDateTime).ToString();
                //    }
                //}
            }
            else
            {
                //「儲存格格式」為「通用格式」,輸入數字,DataType 會為 null
                currentcellvalue = currentcell.InnerText;
                //currentcellvalue = currentcell.CellValue.ToString();
            }

            return currentcellvalue;
        }

    }
}

(完)