導出報表、導入數據是企業級應用標配。本文對比 JExcelApi(僅支援 .xls)與 Apache POI(支援 .xls/.xlsx、功能豐富)的核心 API、樣式處理、大數據流式寫入、常見坑點,助你選型落地。
Workbook (頂層) ├── Sheet (工作表) │ ├── Cell (單元格) │ │ ├── Label (字符串) │ │ ├── Number (數字) │ │ ├── DateTime (日期) │ │ └── Formula (公式) │ └── 合併單元格、行高列寬設置 └── 格式化:WritableFont + WritableCellFormat
// 1. 創建可寫工作簿
WritableWorkbook wwb = Workbook.createWorkbook(new File("report.xls"));
WritableSheet sheet = wwb.createSheet("Sheet1", 0);
// 2. 樣式:字體、對齊、邊框、背景色
WritableFont font = new WritableFont(WritableFont.ARIAL, 12, WritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE, Colour.BLUE);
WritableCellFormat headerFormat = new WritableCellFormat(font);
headerFormat.setAlignment(Alignment.CENTRE);
headerFormat.setBackground(Colour.GRAY_25);
headerFormat.setBorder(Border.ALL, BorderLineStyle.THIN);
// 3. 寫入標題(合併單元格)
sheet.mergeCells(0, 0, 4, 0); // A1:E1
Label title = new Label(0, 0, "2024 年銷售報表", headerFormat);
sheet.addCell(title);
// 4. 寫入數據行
for (int i = 0; i < dataList.size(); i++) {
SaleRecord r = dataList.get(i);
sheet.addCell(new Label(0, i+1, r.getProduct()));
sheet.addCell(new Number(1, i+1, r.getQty()));
sheet.addCell(new Number(2, i+1, r.getAmount()));
// 日期格式
WritableCellFormat dateFmt = new WritableCellFormat(new DateFormat("yyyy-MM-dd"));
sheet.addCell(new DateTime(3, i+1, r.getSaleDate(), dateFmt));
}
// 5. 設置列寬
sheet.setColumnView(0, 30); // 第 0 列寬 30 字符
// 6. 寫入磁盤並關閉
wwb.write();
wwb.close();
Workbook rb = Workbook.getWorkbook(new File("report.xls"));
Sheet sheet = rb.getSheet(0);
for (int i = 1; i < sheet.getRows(); i++) { // 跳過標題行
String product = sheet.getCell(0, i).getContents();
double qty = Double.parseDouble(sheet.getCell(1, i).getContents());
// ...
}
rb.close();
Workbook (介面) ├── HSSFWorkbook (.xls) / XSSFWorkbook (.xlsx) ├── Sheet │ ├── Row │ │ ├── Cell │ │ │ ├── CellStyle (樣式) │ │ │ ├── DataFormat (數據格式) │ │ │ └── Font (字體) │ └── 合併區域、行/列分組、凍結窗格、圖片、圖表、數據驗證 └── SXSSFWorkbook (流式寫入,低內存)
// 1. 創建樣式(從 Workbook 獲取)
CellStyle headerStyle = workbook.createCellStyle();
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setColor(IndexedColors.WHITE.getIndex());
headerFont.setFontHeightInPoints((short) 12);
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headerStyle.setAlignment(HorizontalAlignment.CENTER);
headerStyle.setBorderBottom(BorderStyle.THIN);
// 2. 日期格式
CellStyle dateStyle = workbook.createCellStyle();
DataFormat fmt = workbook.createDataFormat();
dateStyle.setDataFormat(fmt.getFormat("yyyy-MM-dd"));
// 3. 應用樣式
Cell cell = row.createCell(0);
cell.setCellValue("標題");
cell.setCellStyle(headerStyle);
// 保留最近 100 行內存,其餘刷盤到臨時文件
try (SXSSFWorkbook wb = new SXSSFWorkbook(100)) {
Sheet sheet = wb.createSheet("BigData");
// 正常創建 Row/Cell/Style,API 與 XSSF 一致
for (int i = 0; i < 1_000_000; i++) {
Row row = sheet.createRow(i);
row.createCell(0).setCellValue("Row-" + i);
// ...
}
try (FileOutputStream out = new FileOutputStream("big.xlsx")) {
wb.write(out); // 一次性寫入磁盤
}
} // 自動清理臨時文件
| 維度 | JExcelApi (jxl) | Apache POI |
|---|---|---|
| 文件格式 | 僅 .xls (BIFF8) | .xls (HSSF) + .xlsx (XSSF/SXSSF) |
| JAR 體積 | ~300 KB | ~3 MB (poi + poi-ooxml + xmlbeans) |
| 功能豐富度 | 基礎讀寫、樣式、合併 | 全功能:圖表、樞紐表、數據驗證、宏、簽名、加密 |
| 大文件支援 | ❌ 全量內存 | ✅ SXSSF 流式寫入、SAX 事件式讀取 |
| 性能 | 小文件較快 | 大文件優勢明顯 |
| 維護狀態 | 停止更新 (最後 2009) | 活躍維護 (Apache 項目) |
| 推薦場景 | 舊項目維護、極簡導出、受限環境 | **新項目首選**、複雜報表、大數據、.xlsx 需求 |
CellStyle、Font、DataFormat **必須從 Workbook 創建**,全局複用,不可在循環中重複創建(會導致樣式表溢出,拋 IllegalStateException: The maximum number of Cell Styles was exceeded)cell.setCellValue("123") 會存成字符串,導致 Excel 提示「數字儲存為文本」,請用 cell.setCellValue(123) 或 cell.setCellType(CellType.NUMERIC)cell.setCellValue(date) + cellStyle.setDataFormat(fmt.getFormat("yyyy-MM-dd"))sheet.setColumnWidth(col, 256 * 20) 單位為 1/256 字符寬度,JXL sheet.setColumnView(col, 20) 直接用字符數Workbook 實現 Closeable,**必須 try-with-resources** 關閉,否則臨時文件殘留、文件句柄洩漏WorkbookFactory.create(inputStream) 自動識別 .xls/.xlsx