2011年9月26日 星期一

關於在 64位元的 Win7 上匯入 excel 的不堪往事

以前對的事,現在不一定對。自從電腦從 XP 升級到 win7、從 32 位元升級到 64 位元後,這感觸就越來越深了。

以簡單的程式範例來說:


.aspx
<input id="File1" runat="server" name="File1" size="42" style="width: 300px" type="file">
<asp:Button ID="btnImport" runat="server" Text="匯入" onclick="btnImport_Click" />
.aspx.cs
protected void btnImport_Click(object sender, EventArgs e)
{
    //將要匯入的 excel file,先儲存在 IIS Server 的系統暫存目錄.
    HttpPostedFile uploadFile = Request.Files[0];
    string strFileSavePath = Path.GetTempPath();
    string xlsFullName = string.Format(@"{0}/{1}.xls", strFileSavePath, Guid.NewGuid());
    uploadFile.SaveAs(xlsFullName);

    #region //讀取 Excel format data.
    string OleConStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + xlsFullName + ";Extended Properties='Excel 8.0;HDR=No;'";
    OleDbConnection OleCn = new OleDbConnection(OleConStr);
    OleDbCommand OleCmd = new OleDbCommand();
    OleCmd.Connection = OleCn;
    string strSQL = @"SELECT * FROM [Sheet1$]";
    OleCmd.CommandText = strSQL;

    string strData = "";
    int i = 0;
    try
    {
        OleCn.Open();
        OleDbDataReader OleDr = OleCmd.ExecuteReader();
        while (OleDr.Read())
        {
            if (i > 0)
            {
                string strRed = OleDr[0].ToString().Trim();
                if (strRed != "")
                {
                    strData += string.Format("{0},", strRed.Trim());
                }
            }
            i += 1;
        }
    }
    catch (Exception ex)
    {
        //如果檔案存在砍掉此暫存檔案
        if (File.Exists(xlsFullName))
            File.Delete(xlsFullName);

        String scriptString = string.Format(@"
    <script language=JavaScript>
    <!-- begin 
    alert('Excel格式錯誤! 詳細資訊:{0}'); 
    //end -->
    </script> 
    ", ex.Message.Replace("'", "\\'"));
        ClientScript.RegisterStartupScript(GetType(), "msg", scriptString);
        return;
    }
    OleCn.Close();
    #endregion

    Response.Write(strData);

}
如果你建立 web 專案時是以 「File System」方式,則執行匯入功能時,可以正常執行。但如果你建立 web 專案是以「Http」方式,則執行匯入功能時,有可能會出錯,為何說有可能呢?因為這問題是由 IIS 設定所導致的。先看看這錯誤訊息長得怎樣: 

Microsoft.Jet.OLEDB.4.0 提供者並未登錄於本機電腦上。 

原來主要原因,是因為Microsoft Jet 不支援 64 位元的版本,因為 Win7 裝完 IIS 後,預設是以 64 位元的方式來啟動應用程式。可以檢視一下自己的 IIS 設定:

如果「啟用32位元應用程式」為 False,則把它改成 True,讓你的專案是以32位元的模式來執行,就可以正常讀取 excel 資料了。

如果你不是使用 Http 的開發模式,也同樣出現「Microsoft.Jet.OLEDB.4.0 提供者並未登錄於本機電腦上。」錯誤訊息,建議可以參考這篇「Microsoft.Jet.OLEDB.4.0 提供者並未登錄於本機電腦上」文章,或參考下方的[補充20120809]。

此外,如果使用者將 office 升級到 2007以後,預設的 excel 檔名已經由 .xls 變成 .xlsx,當我們使用 Microsoft.Jet.OLEDB.4.0 ,會發生「外部資料表不是預期的格式」錯誤訊息,為了能夠讓匯入 excel 的功能跟的上微軟更新的腳步,必須到以下網站下載:

或是 Google 以下關鍵字:AcessDataBaseEngine


你可能會找到:

AccessDatabaseEngine.exe
AccessDatabaseEngine_x64.exe

一開始我以為是要用 _64 .exe 的版本,但下載安裝後,竟然出現:
由於你目前已安裝 32 位元的 Office 產品,因此無法安裝 64 位元版本的 Microsoft Access Database Engine 2010...

我當時還傻傻的把我的 office 移除,然後去找 64 位元的 office 來裝,最後因為找不到 64 位元的 office 而作罷(到底有沒有 64 位元的 office ,至今我還是沒有找到)。這時候,你只要安裝 AccessDatabaseEngine.exe 版本就可以,別花時間去移除你的 office 了。

安裝完畢後,原來的程式,有個地方需要調整:

將原先:

string OleConStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + xlsFullName +
";Extended Properties='Excel 8.0;HDR=No;'";

改成:
string OleConStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + xlsFullName + ";Extended Properties='Excel 12.0 Xml;HDR=No;'";


這樣就可以順利完成 excel 匯入功能了。



[補充20120809]
如果不是使用 Http 的開發模式,可以在專案的專案名稱屬性裡,將建置(Build)裡的平台目標(Platform target) 設為 x86。

如下圖:


參考:

沒有留言:

張貼留言