Java 讀取 Excel 文件(xls, xlsx) – 使用 Apache POI
小蛙很久很久以前發過一篇 Java + Excel = JXL,主要講解怎麼用 Java 處理 Excel,當時使用的是 jxl 這個套件,不過這個套件有一個很大的問題,就是只能處理 xls 的檔案,xlsx 沒有辦法處理,這篇要介紹的 Apache POI 則可以用來處理 xls 跟 xlsx。
使用套件
小蛙這邊說明自己下載 jar 的方式,首先到這邊下載 Apache POI,下載回來解壓縮之後,會得到一堆 jar,最簡單最簡單就是先把下面這些 jar 通通引入
通通引入之後,小蛙放上參考網路上資料後,改成自己適用的功能片段,主要作法是先讀取 Excel 裡的所有資料丟到 List<List<String>> 裡面,再透過操作 List<List<String>> 的資料達到目的,當然也可以改成最直觀的方式,直接讀取特定欄位直接做處理。(不一定要用這種全部讀出來再去處理的方式,也可以直接一格一格讀出來處理),下面只是列出一些 function,把它改成自己需要的方式就可以了。
操作流程大概是這樣
讀取 xls / xlsx 檔案
第一步就是讀取 excel 檔案,這邊多做了一件事情就是區分出 xls 跟 xlsx,用一個 if 判斷是分別 new 出 HSSFWorkbook / XSSFWorkbook 物件。
// 從路徑中讀取 Excel
default Workbook getWorkbook(String path) throws FileNotFoundException, IOException {
Workbook wb = null;
if(path == null) return null;
String extString = path.substring(path.lastIndexOf("."));
InputStream is = new FileInputStream(path);
if(XLS.equals(extString)){
wb = new HSSFWorkbook(is);
}else if(XLSX.equals(extString)){
wb = new XSSFWorkbook(is);
}
return wb;
}讀取 sheet
從上面取得的 workbook 中,讀取特定頁籤,這個 sheetNo 從 0 開始計算,也就是說第一個頁籤的話要傳入 0,第二個頁籤傳入 1,以此類推。
// 讀取要用的 Sheet
default Sheet getSheet(Workbook workbook, int sheetNo){
return workbook.getSheetAt(sheetNo);
}遍尋 rows(橫的)遍尋 columns(直的)
這邊跟 jxl 比較不同的地方在於,必須先把 row 取出來,然後取得最後一個 row 跟最後一個 column,要注意的是取得 colnum 的時候,要先判斷取出的 row 是不是 null,不然會噴錯喔!(小蛙這邊懶得改了,自己要記得加上判斷喔),以及 index 都是從 0 開始計算,然後每一格儲存格取出的資料都放在 List<List<String>>。中間 readCell 部份內容請往下看。
// 把所有欄位讀出成 List<List<String>>
default List<List<String>> readFields(Workbook workbook, int sheetNo, int firstRow, int firstCol) throws Exception {
Sheet sheet = workbook.getSheetAt(sheetNo);
Row row = sheet.getRow(0);
int rownum = sheet.getPhysicalNumberOfRows();
int colnum = row.getPhysicalNumberOfCells();
List<List<String>> list = new ArrayList<>();
List<String> _inner;
for(int i = firstRow; i < rownum; i++){
row = sheet.getRow(i);
_inner = new ArrayList<>();
if(row != null){
for(int j = firstCol; j < colnum; j++){
_inner.add(readCell(row.getCell(j)));
}
list.add(_inner);
}else{
break;
}
}
return list;
}轉換型態
跟 jxl 不一樣的部份是,jxl 可以直接取得字串型態的資料,但是 poi 必須根據不同的形態來呼叫不同的方法取得內容,下面是參考網路上看到的程式碼做的修改,原始來源不太記得了,大致上符合小蛙的需求,可以直接複製回去,再依自己的需求修改。
// 小蛙自己要吐出的格式
default String readCell(Cell cell){
return (String) getCellFormatValue(cell);
}
default Object getCellFormatValue(Cell cell){
Object cellValue = null;
if(cell!=null){
switch(cell.getCellType()){
case NUMERIC:
cellValue = df.format(cell.getNumericCellValue());
break;
case FORMULA:
if(DateUtil.isCellDateFormatted(cell)){
cellValue = cell.getDateCellValue();
}else{
cellValue = String.valueOf(cell.getNumericCellValue());
}
break;
case STRING:
cellValue = cell.getRichStringCellValue().getString();
break;
default:
cellValue = "";
}
}else{
cellValue = "";
}
return cellValue;
}打完收工,把這些 code 改成自己需求之後組合起來應該就可以順利動囉!
Excel 相關文章: