如何用Java跨工作簿批量复制Excel工作表(非逐单元格复制)
在Java中高效复制整个Excel工作表(无需遍历单元格)
绝对可以!而且这正是解决大Excel文件复制性能问题的关键方案——直接操作工作表的底层结构,跳过逐单元格遍历的繁琐过程,性能提升非常明显。
为什么逐单元格复制性能差?
当数据量较大时,逐单元格复制需要遍历每一个单元格,还要处理单元格样式、公式、数据类型等细节,不仅代码繁琐,还会产生大量的内存开销和IO操作,很容易导致程序卡顿甚至内存溢出。
解决方案:使用Apache POI直接复制工作表结构
Java生态中处理Excel最常用的库是Apache POI,它提供了直接复制整个工作表的API,无需手动遍历单元格。下面是具体实现步骤:
1. 准备依赖
首先在你的Maven项目中添加Apache POI相关依赖:
<dependencies> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.5</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.5</version> </dependency> <!-- 处理超大文件时添加流式依赖 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.2</version> </dependency> </dependencies>
2. 核心代码实现
这里分两种场景:常规文件(XSSF)和超大文件(SXSSF,流式处理避免内存溢出)。
场景一:处理常规大小的Excel文件(.xlsx)
import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class ExcelSheetCopy { public static void main(String[] args) { try ( // 打开源工作簿 XSSFWorkbook sourceWorkbook = new XSSFWorkbook(new FileInputStream("source.xlsx")); // 打开或创建目标工作簿 XSSFWorkbook targetWorkbook = new XSSFWorkbook(new FileInputStream("target.xlsx")) ) { // 获取要复制的源工作表 XSSFSheet sourceSheet = sourceWorkbook.getSheet("Sheet1"); // 直接复制整个工作表到目标工作簿,自动处理数据、样式、公式、合并单元格 String newSheetName = "Copied_Sheet1"; targetWorkbook.cloneSheet(sourceWorkbook.getSheetIndex(sourceSheet), newSheetName); // 保存目标工作簿 try (FileOutputStream fos = new FileOutputStream("target.xlsx")) { targetWorkbook.write(fos); } System.out.println("工作表复制完成!"); } catch (IOException e) { e.printStackTrace(); } } }
场景二:处理超大Excel文件(避免内存溢出)
如果你的工作表数据量极大(比如几十万行),推荐使用SXSSF(流式处理),它会将部分数据写入磁盘,减少内存占用:
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class LargeExcelSheetCopy { public static void main(String[] args) { try ( XSSFWorkbook sourceWorkbook = new XSSFWorkbook(new FileInputStream("large_source.xlsx")); // 创建SXSSF工作簿,设置内存中保留的行数(比如100行,超出的写入临时文件) SXSSFWorkbook targetWorkbook = new SXSSFWorkbook(100) ) { XSSFSheet sourceSheet = sourceWorkbook.getSheet("Large_Sheet"); // 复制源工作表的结构和数据到SXSSF工作簿 Sheet targetSheet = targetWorkbook.createSheet("Copied_Large_Sheet"); // 复制工作表的所有内容(包括样式、公式、合并单元格) copySheet(sourceWorkbook, targetWorkbook, sourceSheet, targetSheet); try (FileOutputStream fos = new FileOutputStream("large_target.xlsx")) { targetWorkbook.write(fos); } // 清理临时文件 targetWorkbook.dispose(); System.out.println("超大工作表复制完成!"); } catch (IOException e) { e.printStackTrace(); } } // 自定义复制方法,适配SXSSF场景 private static void copySheet(XSSFWorkbook sourceWB, SXSSFWorkbook targetWB, XSSFSheet sourceSheet, Sheet targetSheet) { // 复制列宽 for (int i = 0; i <= sourceSheet.getLastColumnNum(); i++) { targetSheet.setColumnWidth(i, sourceSheet.getColumnWidth(i)); } // 复制合并单元格 sourceSheet.getMergedRegions().forEach(region -> targetSheet.addMergedRegion(region)); // 复制行(包括单元格数据、样式、公式) sourceSheet.forEach(row -> { try { targetSheet.createRow(row.getRowNum()); row.forEach(cell -> { targetSheet.getRow(row.getRowNum()).createCell(cell.getColumnIndex()).setCellValue(cell.getStringCellValue()); // 复制单元格样式 targetSheet.getRow(row.getRowNum()).getCell(cell.getColumnIndex()).setCellStyle(cell.getCellStyle()); }); } catch (Exception e) { e.printStackTrace(); } }); } }
关键注意事项
- 样式与公式:
cloneSheet()方法会自动复制单元格样式、公式、数据格式,无需手动处理;对于SXSSF的场景,需要手动复制样式(如上面代码所示)。 - 图片与图表:如果源工作表包含图片或图表,
cloneSheet()不会自动复制这些元素,需要额外通过Drawing对象手动复制绘图内容。 - 公式引用调整:如果源工作表中的公式引用了其他工作簿的单元格,复制后需要手动更新公式引用;如果是同一工作簿内的引用,
cloneSheet()会自动调整。
这样操作的性能会比逐单元格复制提升几个数量级,完全能应对大数据量的工作表复制需求。
内容的提问来源于stack exchange,提问作者Kushal Rastogi
相关产品推荐
相关产品推荐

