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 改成自己需求之後組合起來應該就可以順利動囉!

您可能也會喜歡…

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *