發表文章

使用 NPOI 設定欄位(CELL)樣式與寬度

圖片
如何使用 NPOI 來設定CELL(欄位)的樣式:邊框、底色、字形,等等 底下是個 樣式類別檔案,把常用的欄位形態定義好,以後直接取用 DefXSSFstyle.cs using System.Drawing; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using NPOI.HSSF.Util; namespace XssSTYLE {     /// <summary>     /// 已經定義好的欄位樣式,如果需要新樣式,複製程式碼並賦與新名稱,修改樣式產生程式碼即可使用     /// </summary>     class DefXSSFstyle     {         /// <summary>         /// 抬頭樣式 - 01         /// 灰色底色,白色字,正黑體,無邊框         /// </summary>         /// <param name="wb"></param>         /// <returns></returns>         public XSSFCellStyle Banner01(IWorkbook wb)         {             XSSFCellStyle csh = (XSSFCellStyle)wb.CreateCellStyle();             csh.Alignment = HorizontalAlignment.Center;   ...

關於 NPOI 取得 列 (Row) 和 欄(Cell) 數量

圖片
關於 NPOI 裏面如何取得 列(Row) 與欄(Cell)的數量。 NPOI 對於 IRow 或 ICell 沒有類似集合數量的 count 或是 length 可以取得, 可是相對的有 FirstRowNum / LastRowNum / FirstCellNum / LastCellNum 可以用。 它代表是 首列位置 / 末列位置 / 首欄位置 / 末欄位置 但是非常奇異的是,這兩種的取出值卻完全不是這麼一回事 正常來說,以位置來看的話, C# 計算是從 0 開始 因此以上圖 EXCEL來看應該是: FirstRowNum = 0 LastRowNum = 10 FirstCellNum  = 0 LastCellNum  = 10 列(Row) 和 欄(Cell) 和都 各11個 但是,我們實際把它取出來看卻發現詭異事情了 Console.WriteLine("FirstRowNum = " + ws1.FirstRowNum.ToString() + " ,LastRowNum = " + ws1.LastRowNum.ToString()); Console.WriteLine("FirstCellNum = " + ws1.GetRow(0).FirstCellNum.ToString() + " ,LastCellNum = " + ws1.GetRow(0).LastCellNum.ToString()); 結果: 看! LastCellNum 居然是 11  NPOI 有太多小問題真的很想吐槽了 這個問題 去年被發現 ,但是至今尚未改善 如要參照這個屬性一定要非常小心,哪天突然修正好,你的程式可能也要跟著更新與修正了。

關於 NPOI 的 ISheet.RemoveRow 會清除到錯誤的列

圖片
關於 NPOI 套件裏面的 ISheet.RemoveRow 會移除到錯誤的列 的問題 如上圖,我使用如下指令: // 移除最末行 ws1.RemoveRow(ws1.GetRow(10)); 正確來說,它應該會移除第11行的 統計列,但是卻把第10列移除了? ISheet.GetRow 的陣列是從 0 開始的。 如果你用 // 移除第一行 ws1.RemoveRow(ws1.GetRow(0)); 則甚麼事都不會發生,也就是RemoveRow處理的位置是錯誤的。 這個問題好像 在 2016年就有人提出 了,到現在還沒改善.... 使用上還是要小心

C# 使用NPOI 把資料寫到excel檔案(xlsx)

圖片
利用 NPOI 套件產生如上圖的內容到一個excel檔案 本案例 C# 為 .Net 4.5 ,NPOI 為 2.5.1 版 程式碼如下: // 樣式元件 DefXSSFstyle style = new DefXSSFstyle(); IWorkbook wb = new XSSFWorkbook(); // 建立分頁賦予分頁名稱 ISheet ws1 = wb.CreateSheet("統計表"); // 建立數字陣列 10 X 10 for(int i = 1; i<= 10; i++) {     IRow row0 = ws1.CreateRow(i - 1);     for (int j = 1; j <= 10; j++)     {         ICell cell0 = row0.CreateCell(j - 1);         cell0.SetCellValue(((i - 1) * 10) + j);     } } // 建立合計 ASCIIEncoding aSCII = new ASCIIEncoding(); XSSFCellStyle cssf = style.Field09(wb); IRow subRow = ws1.CreateRow(ws1.LastRowNum + 1); for(int k = 1; k <= 10; k++) {     // 設定公式     string headChar = aSCII.GetString(new byte[] { (byte)(64 + k) });     ICell subCell = subRow.CreateCell(k - 1);     subCell.SetCellFormula("SUM(" + headChar + "1:" + headChar + ws1.GetRow(0).LastCellNum.ToString() + ")");     // 加入樣式   ...

如何在網頁中呼叫windows本地執行程式 How to run windows application (.exe) in HTML

圖片
有時候我們希望在網頁上開啟本地端的應用程式,但是受限於安全性的關係,通常流覽器都不允許執些開啟本地『執行程式』 在 IE 底下,其實可以透過 ActiveXObject 內建物件建立起 wscript.shell 介面,利用此介面來呼叫本地端程式(其實不一定是程式,已註冊文件類型都可以透過 wscript shell 來開啟。 常見方法如下: <html> <head> <script language="javascript"> function Run(strPath) { var objShell = new ActiveXObject("wscript.shell"); objShell.exec(strPath); objShell = null; } </script> </head> <body> <h1>Call target file : D:\Apps\procexp.exe</h1> <BUTTON class=button onclick="Run('D:\Apps\procexp.exe')">執行 Procexp</BUTTON> </body> </html> 上面就是利用 wscript.shell 呼叫指定程序 procexp.exe 問題是... 它是 IE Only 而且,受限於IE版本的關係,比較新版的 IE 必須要去作安全設定才能整常使用,相當不實用。 那,是否有其他方式呼叫本地應用程式呢? 有的,那就是使用自定義的協定讓瀏覽器接受,例如:eD2k:// VeryCD://等等 如上圖如果利用自訂義的協定就可以讓瀏覽器向註冊表請求自定義協定的動作 因此,必須自己創建協定(不可以和目前使用的協定名稱相同) 例如我要自定義一個協定名稱叫 ZzTest:// ,接下來作法如下 一、開啟註冊登錄表       使用命令列模式(使用者必須有系統管理權限) 輸入 Regedit ,然後 Enter 二、建立...

java.lang.NoSuchMethodError : org.apache.poi.poifs.filesystem.POIFSFileSystem.hasPOIFSHeader(Ljava/io/InputStream;)Z 問題解決方法

圖片
這個是在使用 POI 讀取 EXCEL 的 xlsx 檔案造成的 LOCAL.WorkBook = WorkBookFactory.create(FileStream); 使用 WorkBookFactory.create 時內部會呼叫 POIFSFileSystem.hasPOIFSHeader 函式。  如果呼叫失敗就出現這個錯誤訊息。 所以正常來說 POIFSFileSystem.class 裡面是包含 hasPOIFSHeader 函式的。 看大部分網路上的論壇討論結果或是意見,通常是 POI 所需使用的 jar 檔案使用了不匹配/不同版本的套件導致。 但這個問發現在我另一個 jetty 版的 Railo 4.0.4.001 伺服器上卻不會發生。 為什麼?兩個伺服器版本都是一樣的啊?裡面套件也應該相同的啊? 為此,我便進行研究了一下。 1、 發生這個錯誤 的伺服器是以 Tomcat7 執行的伺服器,而另一個 不會發生 這個錯誤的是以 jetty 執行的伺服器。而兩方的版本都是當初官方公佈的 4.0.4.001 版本。 2、比對兩邊使用 POI 的 jar 檔案,雙方的檔案尺寸是相同的,檔案數量也相同。     在此處 POI 相關的 jar 共有4個,這些都是同時隨伺服器版本一起發佈的,不是我另外安裝的,應該不會存在版本問題吧。 3、如果 POIFSFileSystem.class 不包含 hasPOIFSHeader 函式,理論上 jetty 伺服器也會出現錯誤。結果卻沒有發生這個錯誤,代表 POIFSFileSystem.class 是正確的。 但,為甚麼? 所以我用解壓縮軟體來觀察 jar 檔案的成員。 發現了奇怪的的是在 apache-poi.jar 和 apache-poi-tm-extractors.jar 裡面都出現了成員 POIFSFileSystem.class ,而且檔案尺寸完全不一樣! 而且路徑都在 org.apache.poi.poifs.filesystem 下,我猜這就是貓膩了。 因為在這種情況下只會有一個成員會被載入成功,至於是哪一個先被載入要看伺服器核心的 jav...

coldfusion component (CFC) 另一種用法

圖片
一般 CFC 的寫法大概會像上面這樣: 而呼叫方式如下: <cfinvoke component= " COM.extfunc " method= " myescape " returnvariable= " escstr " >     <cfinvokeargument name= " sdata " value= "# myForm.note #" > </cfinvoke> <!--- 返回 escstr ---> <cfoutput> #escstr# </cfoutput> 上面這種方式屬於純 TAG 寫法,寫起來超麻煩,尤其參數很多時就會寫出一堆  <cfinvokeargument>,真是快昏倒了。 其實,也可以使用創建物件方式來使用這個 Component,會方便許多。 我們把上面的 cfc 改成下面方式 <cfcomponent displayname= " extfunc " hint= " 擴充功能 " >       <cffunction name= " Init " access= " public " returntype= " QueryUtility " output= " false "            hint= " Returns an initialized QueryUtility instance. " >           <!--- Return This reference. --->            <cfreturn THIS />       </cffunction>       <cffunction name= "myescape" access= "public" ret...