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
相关产品推荐
相关产品推荐

