You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Excel合并后仅单个工作表保留原样式,如何恢复所有表原始布局?

问题原因分析

你的代码中使用XSSFRangeCopier进行范围复制时,仅复制了单元格的基础内容和部分样式,但未完整复制单元格的边框、填充等样式属性;同时新创建的目标工作表会继承工作簿的默认样式(可能带边框),导致原文件中无显式样式的单元格被覆盖成带边框的默认样式。另外,循环内重复调用workbookTo.write也可能引发样式写入异常。

解决方案

替换范围复制逻辑为逐行逐单元格完整复制样式,并将文件写入操作移至所有工作表合并完成后执行:

修改后的完整代码

private void mergeExcelFiles(String excelFilesPath) {
    Map<String, List<List<String>>> moduleReportFiles = fileNames.entrySet().stream().collect(groupingBy(
            e -> e.getKey().substring(0, e.getKey().lastIndexOf(".")), mapping(e -> e.getValue(), toList())));

    Workbook workbookTo;
    Workbook workbookFrom;

    for (Entry<String, List<List<String>>> moduleNameReportsList : moduleReportFiles.entrySet()) {
        List<String> files = moduleReportFiles.get(moduleNameReportsList.getKey()).stream().flatMap(List::stream)
                .collect(Collectors.toList());

        files = files.stream().sorted().collect(toList());
        File f;
        if (files.size() < 1) {
            continue;
        } else if (files.size() == 1) {
            f = new File(files.get(0));
            f.renameTo(new File(excelFilesPath + "/" + moduleNameReportsList.getKey() + ".xlsx"));
        } else {
            try {
                workbookTo = new XSSFWorkbook(new File(files.get(0)));
                f = new File(files.get(0));
                f.delete();
                files.remove(0);

                for (String file : files) {
                    workbookFrom = new XSSFWorkbook(new File(file));
                    for (int sheetIndex = 0; sheetIndex < workbookFrom.getNumberOfSheets(); sheetIndex++) {
                        XSSFSheet sheetFrom = (XSSFSheet) workbookFrom.getSheetAt(sheetIndex);
                        // 创建目标工作表,保留原工作表名称
                        XSSFSheet sheetTo = (XSSFSheet) workbookTo.createSheet(sheetFrom.getSheetName());

                        // 复制工作表的基本属性(行高、列宽等)
                        sheetTo.setDefaultRowHeight(sheetFrom.getDefaultRowHeight());
                        sheetTo.setDefaultRowHeightInPoints(sheetFrom.getDefaultRowHeightInPoints());
                        // 复制列宽
                        for (int j = 0; j < sheetFrom.getPhysicalNumberOfRows(); j++) {
                            Row row = sheetFrom.getRow(j);
                            if (row != null) {
                                for (int k = 0; k < row.getLastCellNum(); k++) {
                                    sheetTo.setColumnWidth(k, sheetFrom.getColumnWidth(k));
                                }
                            }
                        }

                        // 逐行逐单元格复制内容和完整样式
                        int lastRow = sheetFrom.getLastRowNum();
                        for (int i = 0; i <= lastRow; i++) {
                            Row rowFrom = sheetFrom.getRow(i);
                            if (rowFrom == null) {
                                continue;
                            }
                            Row rowTo = sheetTo.createRow(i);
                            // 复制行高
                            rowTo.setHeight(rowFrom.getHeight());
                            int lastCol = rowFrom.getLastCellNum();
                            for (int j = 0; j < lastCol; j++) {
                                Cell cellFrom = rowFrom.getCell(j);
                                if (cellFrom == null) {
                                    continue;
                                }
                                Cell cellTo = rowTo.createCell(j);

                                // 复制单元格值
                                switch (cellFrom.getCellType()) {
                                    case STRING:
                                        cellTo.setCellValue(cellFrom.getStringCellValue());
                                        break;
                                    case NUMERIC:
                                        if (DateUtil.isCellDateFormatted(cellFrom)) {
                                            cellTo.setCellValue(cellFrom.getDateCellValue());
                                        } else {
                                            cellTo.setCellValue(cellFrom.getNumericCellValue());
                                        }
                                        break;
                                    case BOOLEAN:
                                        cellTo.setCellValue(cellFrom.getBooleanCellValue());
                                        break;
                                    case FORMULA:
                                        cellTo.setCellFormula(cellFrom.getCellFormula());
                                        break;
                                    case BLANK:
                                        cellTo.setCellType(CellType.BLANK);
                                        break;
                                    default:
                                        cellTo.setCellValue(cellFrom.getStringCellValue());
                                }

                                // 复制完整单元格样式(包括边框、字体、对齐、填充等)
                                CellStyle styleFrom = cellFrom.getCellStyle();
                                CellStyle styleTo = workbookTo.createCellStyle();
                                styleTo.cloneStyleFrom(styleFrom);
                                cellTo.setCellStyle(styleTo);
                            }
                        }
                    }
                    // 删除源文件
                    f = new File(file);
                    if(f.delete()) {
                        log.info("report file deleted successfully");
                    }
                }

                // 所有工作表合并完成后,统一写入文件
                try (FileOutputStream fos = new FileOutputStream(new File(excelFilesPath + "/" + moduleNameReportsList.getKey() + ".xlsx"))) {
                    workbookTo.write(fos);
                }
                workbookTo.close();

            } catch (InvalidFormatException e1) {
                log.error(e1.getMessage());
            } catch (IOException e1) {
                log.error(e1.getMessage());
            }
        }
    }
}

关键修改点

  • 移除XSSFRangeCopier,改为逐行逐单元格复制,确保每个单元格的完整样式(边框、字体、对齐方式等)被复制
  • 使用CellStyle.cloneStyleFrom()方法完整克隆源单元格的样式,避免默认样式覆盖
  • 将workbookTo.write()移至所有工作表合并完成后,避免重复写入导致的样式混乱
  • 补充复制工作表的基础属性(行高、列宽等),保证布局完全一致

内容的提问来源于stack exchange,提问作者user1167753

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 08:48:09