作者:khotyn
來源:https://blog.khotyn.com/blog/2013/03/01/apache-poi-notes/
最近在寫一個解析 Excel 的程序,需要把從前端上傳上來的 Excel 程序解析成 JSON 格式返回給前端,期間也試過 jxl ,不過它只支持到 Excel 2003。後來轉而使用 apache 的 POI,作為初次使用者,使用過程中遇到了不少的問題:
# 如何引入 XSSF
剛下手寫的時候,直接使用了 HSSFWorkbook 處理 Excel,後來發現它只能處理 2003 的 Excel,而不能處理 2007 版本的 Excel,翻了一下 POI 的文檔,發現處理 2007 的 Excel 需要使用 XSSFWorkbook,但是引入的 POI 包中卻找不到 XSSF 相關的類,原猜想是因為引入了版本較新的 POI,而官方的文檔還是比較老的,因而被誤導。結果發現使用 XSSF 需要額外引入 poi-ooxml 這個 jar 包, XSSF 相關的類都在這個 jar 包中,mvn 依賴如下:
<dependency>
<groupid>org.apache.poi/<groupid>
<artifactid>poi-ooxml/<artifactid>
<version>3.9/<version>
/<dependency>
# 兼容處理 Excel 2003 和 2007
引入了 poi-ooxml 以後就使用 XSSF 來處理,本以為 XSSF 既然能夠處理 Excel 2007,那麼 2003 也該能處理吧?得向下兼容不是?沒想到不行!總不能用擴展名來區別是 2003 還是 2007 吧,後來發現了 WorkbookFactory 這個類,它的 create(InputStream inp) 方法可以根據版本來選擇創建 HSSFWorkbook 還是 XSSFWorkbook,使用者無需關心版本的問題,非常方便!
# 以 String 的形式讀取單元格的數據
要讀取的 Excel 中有一些數據是數字的,單元格的類型是 Numberic 的,而我希望將單元格中的數據都以 String 的形式拿出來。於是當我看到 Cell.getStringCellValue() 這個方法的時候滿心歡喜,但是當用了之後,這貨居然直接給我一個異常,定眼一樣,這方式是 getStringCellValue,而不是 getCellStringValue,真是瞎了眼了。
事實上,Cell 也根本沒有 getCellStringValue 這樣的方法,後來藉助了 SOF,查到了一個方法:
row.getCell(j).setCellType(Cell.CELL_TYPE_STRING);
cellValue = row.getCell(j).getStringCellValue();
是的,就是先把單元格變成 String 類型的,然後再調用 getStringCellValue() 來獲取數據,雖然這方法可行,但是總感覺有點猥瑣,不知大家有沒有更好的方法?
錯誤地使用 getPhysicalNumberOfCells()
遇到的最後一個坑就是使用了 getPhysicalNumberOfCells() 這個方法來獲取一行中單元格的數量以對行的中單元格進行遍歷,依靠這個方法來遍歷會出現的情況就是如果行中間的某些單元格是空的,那麼你就解析不到這一行最後的幾個單元格,原因是因為按照文檔的說明
這個方法只對有值的單元格進行計數,正確的遍歷方法應該用 getFirstCellNum() 和 getLastCellNum() 來確定第一個單元格和最後一個單元格的位置,然後進行遍歷,當然,要注意中間可能會出現空單元的情況,小心 NPE 異常。
另外,我發現很多 POI 的中文介紹資料上遍歷 Excel 的樣例代碼都是採用了 getPhysicalNumberOfCells(),估計作者也沒有經過徹底的測試,或者仔細閱讀官方的文檔和例子,平時大家做開發的時候,還是儘量找官方的介紹資料為好,看二手資料,一不小心就踩坑了。