首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JExcelApi 實現 Excel 按規則拆分:保留格式的多文件導出完整方案

     編輯:Java 相關知識

業務需求:讀取大型 Excel,按業務規則拆分為多個小文件,每文件保持原始單元格格式(字體、邊框、對齊、欄寬、行高)。本文基於 JExcelApi (jxl) 示範完整實作。

Maven 依賴

<dependency>
  <groupId>net.sourceforge.jexcelapi</groupId>
  <artifactId>jxl</artifactId>
  <version>2.6.12</version>
</dependency>

核心邏輯:流式讀取 + 格式複製

public class ExcelSplitter {
    public static void splitByRule(String inputPath, String outputDir, int rowsPerFile) 
            throws IOException, BiffException, WriteException, RowsExceededException {
        
        try (Workbook wb = Workbook.getWorkbook(new File(inputPath))) {
            Sheet sheet = wb.getSheet(0);
            int totalRows = sheet.getRows();
            int totalCols = sheet.getColumns();
            
            int fileIndex = 1;
            int rowPtr = 0;
            
            while (rowPtr < totalRows) {
                // 識別分組邏輯:此處假設第 0 欄為標識欄
                Cell flagCell = sheet.getCell(0, rowPtr);
                if (flagCell.getType() != CellType.LABEL) {
                    rowPtr++;
                    continue;
                }
                
                // 建立新工作簿
                File outFile = new File(outputDir, "split_" + fileIndex + ".xls");
                try (WritableWorkbook wwb = Workbook.createWorkbook(outFile)) {
                    WritableSheet ws = wwb.createSheet("Sheet1", 0);
                    
                    // 複製表頭(第 0、1 行)
                    copyRowWithFormat(sheet, ws, 0, 0, totalCols, true);  // 標題行
                    copyRowWithFormat(sheet, ws, 1, 1, totalCols, false); // 表頭行
                    
                    // 合併標題行單元格
                    ws.mergeCells(0, 0, totalCols - 1, 0);
                    
                    // 設置特定欄寬
                    ws.setColumnView(6, 10);
                    ws.setColumnView(7, 45);
                    ws.setColumnView(8, 27);
                    
                    // 複製數據行
                    int writeRow = 2;
                    while (rowPtr < totalRows) {
                        Cell cell0 = sheet.getCell(0, rowPtr);
                        if (cell0.getType() == CellType.NUMBER) {
                            copyRowWithFormat(sheet, ws, rowPtr, writeRow, totalCols, false);
                            writeRow++;
                            rowPtr++;
                        } else {
                            break; // 遇到非數據行,結束當前文件
                        }
                    }
                    
                    wwb.write();
                    fileIndex++;
                }
            }
        }
    }
    
    private static void copyRowWithFormat(Sheet src, WritableSheet dest, int srcRow, int destRow, 
                                          int cols, boolean isHeader) {
        for (int c = 0; c < cols; c++) {
            Cell srcCell = src.getCell(c, srcRow);
            WritableCellFormat format = createFormat(srcCell, isHeader);
            WritableCell destCell = createCell(srcCell, format);
            dest.addCell(new jxl.write.Label(c, destRow, srcCell.getContents(), format));
            // 複製行高
            if (c == 0) dest.setRowView(destRow, src.getRowView(srcRow));
        }
    }
    
    private static WritableCellFormat createFormat(Cell cell, boolean isHeader) {
        WritableFont font = new WritableFont(
            WritableFont.createFont("宋體"),
            isHeader ? 20 : 12,
            isHeader ? WritableFont.BOLD : WritableFont.NO_BOLD,
            false
        );
        WritableCellFormat format = new WritableCellFormat(font);
        format.setAlignment(Alignment.CENTRE);
        format.setVerticalAlignment(VerticalAlignment.CENTRE);
        format.setBorder(Border.ALL, BorderLineStyle.THIN, Colour.BLACK);
        return format;
    }
}

關鍵技術點

需求JExcelApi 實現
字體/大小/粗體WritableFont + WritableCellFormat
水平/垂直居中Alignment.CENTRE / VerticalAlignment.CENTRE
邊框樣式/顏色Border.ALL, BorderLineStyle.THIN, Colour.BLACK
合併儲存格ws.mergeCells(col1, row1, col2, row2)
欄寬/行高setColumnView / setRowView
數字/日期格式NumberFormat / DateFormat 配合 WritableCellFormat

JExcelApi 限制與現代替代

限制影響替代方案
僅支援 .xls (BIFF8)無法處理 .xlsx、超過 65536 行Apache POI (HSSF/XSSF)
記憶體佔用高大文件易 OOMPOI SXSSF (流式寫入)
不支援圖表/樞紐分析表複雜報表無法保真POI / 商業庫
維護停滯安全漏洞、JDK 相容性風險遷移至 POI

遷移建議:Apache POI 版本

// POI 流式寫入大文件 (SXSSF)
try (SXSSFWorkbook wb = new SXSSFWorkbook(100)) { // 保留 100 行在記憶體
    Sheet sheet = wb.createSheet();
    // ... 建立樣式、寫入數據 ...
    try (FileOutputStream fos = new FileOutputStream("output.xlsx")) {
        wb.write(fos);
    }
    wb.dispose(); // 釋放臨時文件
}

效能優化技巧

  • 樣式複用:建立樣式 Map,避免重複創建 WritableCellFormat
  • 批次寫入:累積 N 行後一次 wwb.write()(需權衡記憶體)
  • 關閉自動刷新:POI 設置 setForceFormulaRecalculation(false)
  • 並行拆分:按分組併發處理,合併輸出

JExcelApi 適合簡單 .xls 維護專案。新專案強烈建議直接使用 Apache POI,獲得 .xlsx 支援、流式處理、活躍社群與長期維護保障。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved