1. 程式人生 > >java讀寫excel(POI,支援xls和xlsx兩種格式)

java讀寫excel(POI,支援xls和xlsx兩種格式)

這應該是一個比較全的示例了,更加複雜的功能可以在此基礎上擴充套件。此示例基於apache的POI類庫,相關jar包就不列舉了。這個類庫很通用,網上很好找。

1、不包含單元格合併的寫excel

	/**
	 * excel匯出到輸出流
	 * 誰呼叫誰負責關閉輸出流
	 * @param os 輸出流
	 * @param excelExtName excel檔案的副檔名,支援xls和xlsx,不帶點號
	 * @param data 
	 * @throws IOException
	 */
	public static void writeExcel(OutputStream os, String excelExtName, Map<String, List<List<String>>> data) throws IOException{
		Workbook wb = null;
		try {
			if ("xls".equals(excelExtName)) {
				wb = new HSSFWorkbook();
			} else if ("xlsx".equals(excelExtName)) {
				wb = new XSSFWorkbook();
			} else {
				throw new Exception("當前檔案不是excel檔案");
			}
			for (String sheetName : data.keySet()) {
				Sheet sheet = wb.createSheet(sheetName);
				List<List<String>> rowList = data.get(sheetName);
				for (int i = 0; i < rowList.size(); i++) {
					List<String> cellList = rowList.get(i);
					Row row = sheet.createRow(i);
					for (int j = 0; j < cellList.size(); j++) {
						Cell cell = row.createCell(j);
						cell.setCellValue(cellList.get(j));
					}
				}
			}
			wb.write(os);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (wb != null) {
				wb.close();
			}
		}
	}

2、包含單元格合併的寫excel

輔助vo

class ExcelData{
	private String value;//單元格的值
	private int colSpan = 1;//單元格跨幾列
	private int rowSpan = 1;//單元格跨幾行
	private boolean alignCenter;//單元格是否居中,預設不居中,如果選擇是,則水平和上下都居中
	public boolean isAlignCenter() {
		return alignCenter;
	}
	public void setAlignCenter(boolean alignCenter) {
		this.alignCenter = alignCenter;
	}
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public int getColSpan() {
		return colSpan;
	}
	public void setColSpan(int colSpan) {
		this.colSpan = colSpan;
	}
	public int getRowSpan() {
		return rowSpan;
	}
	public void setRowSpan(int rowSpan) {
		this.rowSpan = rowSpan;
	}
}

寫excel檔案的邏輯
	/**
	 * excel匯出到輸出流
	 * 誰呼叫誰負責關閉輸出流
	 * @param os 輸出流
	 * @param excelExtName excel檔案的副檔名,支援xls和xlsx,不帶點號
	 * @param data excel資料,map中的key是標籤頁的名稱,value對應的list是標籤頁中的資料。list中的子list是標籤頁中的一行,子list中的物件是一個單元格的資料,包括是否居中、跨幾行幾列以及存的值是多少
	 * @throws IOException
	 */
	public static void testWrite(OutputStream os, String excelExtName, Map<String, List<List<ExcelData>>> data) throws IOException{
		Workbook wb = null;
		CellStyle cellStyle = null;
		boolean isXls;
		try {
			if ("xls".equals(excelExtName)) {
				wb = new HSSFWorkbook();
				isXls = true;
			} else if ("xlsx".equals(excelExtName)) {
				wb = new XSSFWorkbook();
				isXls = false;
			} else {
				throw new Exception("當前檔案不是excel檔案");
			}
			cellStyle = wb.createCellStyle();
			if (isXls) {
				cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
				cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
			} else {
				cellStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
				cellStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
			}
			for (String sheetName : data.keySet()) {
				Sheet sheet = wb.createSheet(sheetName);
				List<List<ExcelData>> rowList = data.get(sheetName);
				//i 代表第幾行 從0開始
				for (int i = 0; i < rowList.size(); i++) {
					List<ExcelData> cellList = rowList.get(i);
					Row row = sheet.createRow(i);
					int j = 0;//j 代表第幾列 從0開始
					for (ExcelData excelData : cellList) {
						if (excelData != null) {
							if (excelData.getColSpan() > 1 || excelData.getRowSpan() > 1) {
								CellRangeAddress cra = new CellRangeAddress(i, i + excelData.getRowSpan() - 1, j, j + excelData.getColSpan() - 1);
								sheet.addMergedRegion(cra);
							}
							Cell cell = row.createCell(j);
							cell.setCellValue(excelData.getValue());
							if (excelData.isAlignCenter()) {
								cell.setCellStyle(cellStyle);
							}
							j = j + excelData.getColSpan();
						} else {
							j++;
						}
					}
				}
			}
			wb.write(os);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (wb != null) {
				wb.close();
			}
		}
	}

測試程式碼
	public static void main(String[] args) throws IOException {
		Map<String, List<List<ExcelData>>> data = new LinkedHashMap<>();
		List<List<ExcelData>> sheet1 = new ArrayList<>();//第一頁
		
		List<ExcelData> list1 = new ArrayList<>();//第一行
		ExcelData excelData = new ExcelData();//第一個單元格
		excelData.setColSpan(6);
		excelData.setRowSpan(1);
		excelData.setValue("xxx");
		excelData.setAlignCenter(true);
		list1.add(excelData);
		
		List<ExcelData> list2 = new ArrayList<>();//第二行
		excelData = new ExcelData();//第一個單元格
		excelData.setColSpan(1);
		excelData.setRowSpan(1);
		excelData.setValue("a");
		list2.add(excelData);
		excelData = new ExcelData();//第二個單元格
		excelData.setColSpan(1);
		excelData.setRowSpan(1);
		excelData.setValue("b");
		list2.add(excelData);
		excelData = new ExcelData();//第三個單元格
		excelData.setColSpan(2);
		excelData.setRowSpan(4);
		excelData.setValue("c");
		excelData.setAlignCenter(true);
		list2.add(excelData);
		excelData = new ExcelData();//第四個單元格
		excelData.setColSpan(2);
		excelData.setRowSpan(2);
		excelData.setValue("d");
		excelData.setAlignCenter(true);
		list2.add(excelData);
		
		List<ExcelData> list3 = new ArrayList<>();//第三行
		excelData = new ExcelData();//第一個單元格
		excelData.setColSpan(1);
		excelData.setRowSpan(1);
		excelData.setValue("e");
		list3.add(excelData);
		excelData = new ExcelData();//第二個單元格
		excelData.setColSpan(1);
		excelData.setRowSpan(1);
		excelData.setValue("f");
		list3.add(excelData);
		list3.add(null);//第三個單元格
		list3.add(null);//第四個單元格
		list3.add(null);//第五個單元格
		list3.add(null);//第六個單元格
		
		List<ExcelData> list4 = new ArrayList<>();//第四行
		excelData = new ExcelData();//第一個單元格
		excelData.setColSpan(1);
		excelData.setRowSpan(1);
		excelData.setValue("i");
		list4.add(excelData);
		excelData = new ExcelData();//第二個單元格
		excelData.setColSpan(1);
		excelData.setRowSpan(1);
		excelData.setValue("j");
		list4.add(excelData);
		list4.add(null);//第三個單元格
		list4.add(null);//第四個單元格
		excelData = new ExcelData();//第五個單元格
		excelData.setRowSpan(1);
		excelData.setColSpan(1);
		excelData.setValue("g");
		list4.add(excelData);
		excelData = new ExcelData();//第六個單元格
		excelData.setRowSpan(1);
		excelData.setColSpan(1);
		excelData.setValue("h");
		list4.add(excelData);
		
		List<ExcelData> list5 = new ArrayList<>();//第五行
		excelData = new ExcelData();//第一個單元格
		excelData.setColSpan(1);
		excelData.setRowSpan(1);
		excelData.setValue("k");
		list5.add(excelData);
		excelData = new ExcelData();//第二個單元格
		excelData.setColSpan(1);
		excelData.setRowSpan(1);
		excelData.setValue("l");
		list5.add(excelData);
		list5.add(null);//第三個單元格
		list5.add(null);//第四個單元格
		excelData = new ExcelData();//第五個單元格
		excelData.setRowSpan(1);
		excelData.setColSpan(1);
		excelData.setValue("m");
		list5.add(excelData);
		excelData = new ExcelData();//第六個單元格
		excelData.setRowSpan(1);
		excelData.setColSpan(1);
		excelData.setValue("n");
		list5.add(excelData);
		
		sheet1.add(list1);
		sheet1.add(list2);
		sheet1.add(list3);
		sheet1.add(list4);
		sheet1.add(list5);
		
		data.put("表1", sheet1);
		
		testWrite(new FileOutputStream(new File("D:/temp/my.xlsx")), "xlsx", data);
	}
}

3、讀取excel,這個方法的返回值帶有一點業務邏輯,適用於沒有單元格合併的excel,並且第一行是title的情況。返回的結果中,把第一行之外的每一個單元格包裝成一個map,key是這個單元格的第一行的數值,也就是標題,value是這個單元格的值。邏輯有些繞,直接看程式碼。
	/**
	 * 適用於第一行是標題行的excel,例如
	 * 姓名	年齡	性別	身高
	 * 張三	25	男	175
	 * 李四	22	女	160
	 * 每一行構成一個map,key值是列標題,value是列值。沒有值的單元格其value值為null
	 * 返回結果最外層的list對應一個excel檔案,第二層的list對應一個sheet頁,第三層的map對應sheet頁中的一行
	 * @throws Exception 
	 */
	public static List<List<Map<String, String>>> readExcelWithTitle(String filepath) throws Exception{
		String fileType = filepath.substring(filepath.lastIndexOf(".") + 1, filepath.length());
		InputStream is = null;
		Workbook wb = null;
		try {
			is = new FileInputStream(filepath);
			
		    if (fileType.equals("xls")) {
		    	wb = new HSSFWorkbook(is);
		    } else if (fileType.equals("xlsx")) {
		    	wb = new XSSFWorkbook(is);
		    } else {
		    	throw new Exception("讀取的不是excel檔案");
		    }
		    
		    List<List<Map<String, String>>> result = new ArrayList<List<Map<String,String>>>();//對應excel檔案
		    
		    int sheetSize = wb.getNumberOfSheets();
		    for (int i = 0; i < sheetSize; i++) {//遍歷sheet頁
		    	Sheet sheet = wb.getSheetAt(i);
		    	List<Map<String, String>> sheetList = new ArrayList<Map<String, String>>();//對應sheet頁
		    	
		    	List<String> titles = new ArrayList<String>();//放置所有的標題
		    	
		    	int rowSize = sheet.getLastRowNum() + 1;
		    	for (int j = 0; j < rowSize; j++) {//遍歷行
		    		Row row = sheet.getRow(j);
		    		if (row == null) {//略過空行
						continue;
					}
		    		int cellSize = row.getLastCellNum();//行中有多少個單元格,也就是有多少列
		    		if (j == 0) {//第一行是標題行
		    			for (int k = 0; k < cellSize; k++) {
			    			Cell cell = row.getCell(k);
			    			titles.add(cell.toString());
			    		}
		    		} else {//其他行是資料行
		    			Map<String, String> rowMap = new HashMap<String, String>();//對應一個數據行
		    			for (int k = 0; k < titles.size(); k++) {
		    				Cell cell = row.getCell(k);
		    				String key = titles.get(k);
		    				String value = null;
		    				if (cell != null) {
								value = cell.toString();
							}
		    				rowMap.put(key, value);
		    			}
		    			sheetList.add(rowMap);
		    		}
		    	}
		    	result.add(sheetList);
		    }
		    
		    return result;
		} catch (FileNotFoundException e) {
			throw e;
		} finally {
			if (wb != null) {
				wb.close();
			}
			if (is != null) {
				is.close();
			}
		}
	}

4、讀取excel,適合於沒有合併單元格且沒有標題行的情況
	/**
	 * 適用於沒有標題行的excel,例如
	 * 張三	25歲		男	175cm
	 * 李四	22歲		女	160cm
	 * 每一行構成一個map,key值是列標題,value是列值。沒有值的單元格其value值為null
	 * 返回結果最外層的list對應一個excel檔案,第二層的list對應一個sheet頁,第三層的map對應sheet頁中的一行
	 * @throws Exception 
	 */
	public static List<List<List<String>>> readExcelWithoutTitle(String filepath) throws Exception{
		String fileType = filepath.substring(filepath.lastIndexOf(".") + 1, filepath.length());
		InputStream is = null;
		Workbook wb = null;
		try {
			is = new FileInputStream(filepath);
			
		    if (fileType.equals("xls")) {
		    	wb = new HSSFWorkbook(is);
		    } else if (fileType.equals("xlsx")) {
		    	wb = new XSSFWorkbook(is);
		    } else {
		    	throw new Exception("讀取的不是excel檔案");
		    }
		    
		    List<List<List<String>>> result = new ArrayList<List<List<String>>>();//對應excel檔案
		    
		    int sheetSize = wb.getNumberOfSheets();
		    for (int i = 0; i < sheetSize; i++) {//遍歷sheet頁
		    	Sheet sheet = wb.getSheetAt(i);
		    	List<List<String>> sheetList = new ArrayList<List<String>>();//對應sheet頁
		    	
		    	int rowSize = sheet.getLastRowNum() + 1;
		    	for (int j = 0; j < rowSize; j++) {//遍歷行
		    		Row row = sheet.getRow(j);
		    		if (row == null) {//略過空行
						continue;
					}
		    		int cellSize = row.getLastCellNum();//行中有多少個單元格,也就是有多少列
	    			List<String> rowList = new ArrayList<String>();//對應一個數據行
	    			for (int k = 0; k < cellSize; k++) {
	    				Cell cell = row.getCell(k);
	    				String value = null;
	    				if (cell != null) {
							value = cell.toString();
						}
	    				rowList.add(value);
	    			}
	    			sheetList.add(rowList);
		    	}
		    	result.add(sheetList);
		    }
		    
		    return result;
		} catch (FileNotFoundException e) {
			throw e;
		} finally {
			if (wb != null) {
				wb.close();
			}
			if (is != null) {
				is.close();
			}
		}
	}