POI 复制多个excel文件 合并为一个总excel文件

本文介绍了一种高效批量合并多个Excel文件的方法。通过一次性加载模板文件并逐条填充数据,显著提高了处理速度。提供了完整的Java代码示例,包括如何使用POI库复制样式和合并单元格。

参考:
http://blog.youkuaiyun.com/wutbiao/article/details/8696446
项目中需求:
将12个excel文件合并为一个总excel文件。首先想的思路是读取每个excel文件的sheet然后再copy到总excel文件里,查阅了前辈写的POI工具类,最后生成成功。但逐次打开12个excle文件效率很低,耗时9s,决定换其他思路开发。现将此工具类代码暂放,以后再学习使用。

import java.util.Iterator;
import org.apache.poi.ss.usermodel.DateUtil; 
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;


public class POIUtils {
	public class XSSFDateUtil extends DateUtil {  
	     
	}  
	public static void copyCellStyle(XSSFCellStyle fromStyle, XSSFCellStyle toStyle) {
		
		toStyle.cloneStyleFrom(fromStyle);//此一行代码搞定
		//下面统统不用
		/*
		//对齐方式
        toStyle.setAlignment(fromStyle.getAlignment());  
        //边框和边框颜色  
        toStyle.setBorderBottom(fromStyle.getBorderBottom());  
        toStyle.setBorderLeft(fromStyle.getBorderLeft());  
        toStyle.setBorderRight(fromStyle.getBorderRight());  
        toStyle.setBorderTop(fromStyle.getBorderTop());  
        toStyle.setTopBorderColor(fromStyle.getTopBorderColor());  
        toStyle.setBottomBorderColor(fromStyle.getBottomBorderColor());  
        toStyle.setRightBorderColor(fromStyle.getRightBorderColor());  
        toStyle.setLeftBorderColor(fromStyle.getLeftBorderColor());   
        //背景和前景  
        //toStyle.setFillPattern(fromStyle.getFillPattern());  //填充图案,不起作用,转为黑色  
        toStyle.setFillBackgroundColor(fromStyle.getFillBackgroundColor());  //不起作用
        toStyle.setFillForegroundColor(fromStyle.getFillForegroundColor());  
        toStyle.setDataFormat(fromStyle.getDataFormat());  //数据格式 
        //toStyle.setFont(fromStyle.getFont());  //不起作用
        toStyle.setHidden(fromStyle.getHidden());  
        toStyle.setIndention(fromStyle.getIndention());//首行缩进  
        toStyle.setLocked(fromStyle.getLocked());  
        toStyle.setRotation(fromStyle.getRotation());//旋转  
        toStyle.setVerticalAlignment(fromStyle.getVerticalAlignment());  //垂直对齐
        toStyle.setWrapText(fromStyle.getWrapText()); //文本换行 
        */  
    }  
	public static void mergeSheetAllRegion(XSSFSheet fromSheet, XSSFSheet toSheet) {//合并单元格
		int num = fromSheet.getNumMergedRegions();
		CellRangeAddress cellR = null;
		for (int i = 0; i < num; i++) {
			cellR = fromSheet.getMergedRegion(i);
			toSheet.addMergedRegion(cellR);
		}
	} 
	
	public static void copyCell(XSSFWorkbook wb,XSSFCell fromCell, XSSFCell toCell) {  
        XSSFCellStyle newstyle=wb.createCellStyle();  
        copyCellStyle(fromCell.getCellStyle(), newstyle);  
        //toCell.setEncoding(fromCell.getEncoding());  
        //样式  
        toCell.setCellStyle(newstyle);   
        if (fromCell.getCellComment() != null) {  
            toCell.setCellComment(fromCell.getCellComment());  
        }  
        // 不同数据类型处理  
        int fromCellType = fromCell.getCellType();  
        toCell.setCellType(fromCellType);  
        if (fromCellType == XSSFCell.CELL_TYPE_NUMERIC) {  
            if (XSSFDateUtil.isCellDateFormatted(fromCell)) {  
                    toCell.setCellValue(fromCell.getDateCellValue());  
                } else {  
                    toCell.setCellValue(fromCell.getNumericCellValue());  
                }  
            } else if (fromCellType == XSSFCell.CELL_TYPE_STRING) {  
                toCell.setCellValue(fromCell.getRichStringCellValue());  
            } else if (fromCellType == XSSFCell.CELL_TYPE_BLANK) {  
                // nothing21  
            } else if (fromCellType == XSSFCell.CELL_TYPE_BOOLEAN) {  
                toCell.setCellValue(fromCell.getBooleanCellValue());  
            } else if (fromCellType == XSSFCell.CELL_TYPE_ERROR) {  
                toCell.setCellErrorValue(fromCell.getErrorCellValue());  
            } else if (fromCellType == XSSFCell.CELL_TYPE_FORMULA) {  
                toCell.setCellFormula(fromCell.getCellFormula());  
            } else { // nothing29  
            }  
          
    }  

	public static void copyRow(XSSFWorkbook wb,XSSFRow oldRow,XSSFRow toRow){  
		toRow.setHeight(oldRow.getHeight());
        for (Iterator cellIt = oldRow.cellIterator(); cellIt.hasNext();) {  
            XSSFCell tmpCell = (XSSFCell) cellIt.next();  
            XSSFCell newCell = toRow.createCell(tmpCell.getColumnIndex());  
            copyCell(wb,tmpCell, newCell);  
        }  
    }  
	public static void copySheet(XSSFWorkbook wb,XSSFSheet fromSheet, XSSFSheet toSheet) {   
		mergeSheetAllRegion(fromSheet, toSheet);     
		//设置列宽
        for(int i=0;i<=fromSheet.getRow(fromSheet.getFirstRowNum()).getLastCellNum();i++){ 
        	toSheet.setColumnWidth(i,fromSheet.getColumnWidth(i)); 
        } 
        for (Iterator rowIt = fromSheet.rowIterator(); rowIt.hasNext();) {  
            XSSFRow oldRow = (XSSFRow) rowIt.next(); 
            XSSFRow newRow = toSheet.createRow(oldRow.getRowNum()); 
            copyRow(wb,oldRow,newRow);  
        }  
    }  
	
	
}

业务层处理:

//将所有类型的尽调excel文件合并成一个excel文件
XSSFWorkbook newExcelCreat = new XSSFWorkbook(); 
for(String fromExcelName:fileNameList) {//遍历每个源excel文件,fileNameList为源文件的名称集合
	 InputStream in = new FileInputStream(tempUrl+ File.separator +fromExcelName);
	 XSSFWorkbook fromExcel = new XSSFWorkbook(in);
	 for(int i = 0; i < fromExcel.getNumberOfSheets(); i++) {//遍历每个sheet
		 XSSFSheet oldSheet = fromExcel.getSheetAt(i);
		 XSSFSheet newSheet = newExcelCreat.createSheet(oldSheet.getSheetName()); 
		 POIUtils.copySheet(newExcelCreat, oldSheet, newSheet);
	 } 
 }
 String allFileName=tempUrl+File.separator+"总文件_"+format.format(new Date())+".xlsx";
 FileOutputStream fileOut = new FileOutputStream(allFileName);
 newExcelCreat.write(fileOut); 
 fileOut.flush(); 
 fileOut.close();
 //删除各个源文件
 for(String fromExcelName:fileNameList) {//遍历每个源excel文件
	 File file=new File(tempUrl+File.separator+fromExcelName);
	 if(file.exists()){
		 file.delete();
	 } 
 }

2020.05.14更新博文
 首先不好意思,现在才补充当时的另外一种实现思路。
 因为年代久远,翻了下以前的代码,不知道当时的逻辑是不是解决了效率的问题,各位同学暂且试一下吧。
思路:
 以上弃用的逻辑是遍历读取每个源excel文件,这样肯定耗时。以下的逻辑是只打开读取一次excel源文件,然后将数据塞入,再写出来。
 1.首先定义一个总Excel的模板:allFiles.xlsx,里面每个sheet名字事先定义好,每个sheet里的内容也和各自对应的子Excel文件内容对应好。
在这里插入图片描述
 2.拿到业务数据,遍历每条业务记录,根据目标记录的业务类型+在allFiles.xlsx中对应的sheet,调用各自业务的’下载生成Excel’方法,各自业务操作时处理的都是同一个对象XSSFWorkbook
 3.最后将XSSFWorkbook对象写出
 代码如下:

//1.拿到目标业务数据,封装ddType tableId
if (fileList != null && fileList.size() > 0) {
   for (int i = 0; i < fileList.size(); i++) {
   	String ddType = fileList.get(i).getProfileType();
   	String tableId = fileList.get(i).getCognateTableId();
   	Map<String,String> map=Maps.newHashMap();
   	map.put("ddType", ddType);//ddType:业务类型
   	map.put("tableId", tableId);//tableId:数据库表某条记录的主键id
   	mapList.add(i,map);
   }
}
...
//2.遍历每条记录,根据不同的业务类型进行处理
if (mapList != null && mapList.size() > 0) {
   //2-1.指定总excel的模板文件
   String pathFrom = "/exceltemplates/allFiles.xlsx";   
   @SuppressWarnings("resource")
   XSSFWorkbook fromWorkbook=new XSSFWorkbook(当前类.class.getResourceAsStream(pathFrom)); 
   XSSFWorkbook toWorkbook=new XSSFWorkbook();
   XSSFSheet fromSheet=null;  
   //2-2.遍历,开始生成excle文件的sheet页 
   Map<String,Object> map=new HashMap<String,Object>(); 
   for (int i = 0; i < mapList.size(); i++) {  
   		String ddType = mapList.get(i).get("ddType");
   		String tableId = mapList.get(i).get("tableId");
   		if (ddType.equals("A")) {
   			fromSheet=fromWorkbook.getSheetAt(0);
   			toWorkbook=xxxService.createFile(toWorkbook,fromSheet,tableId);
   		} else if (ddType.equals("B")) {
   			...
   		} 
   		...//省略其他十几个业务类型
   }
}
//3.输出总excle文件到tempurl下
String allDdFilesName = "总文件_" + format.format(new Date()) + ".xlsx";
FileOutputStream workbookOut = new FileOutputStream(tempUrl + allDdFilesName);
toWorkbook.write(workbookOut);
workbookOut.flush();
workbookOut.close(); 
...

  其中某一个业务类的生成excle的方法实现:

public XSSFWorkbook createFile(XSSFWorkbook toWorkbook,XSSFSheet fromSheet,String tableId) throws IOException{  
  	//1.对sheet进行命名
  	XSSFSheet toSheet=toWorkbook.createSheet(); 
  	int sheetAmount=toWorkbook.getNumberOfSheets();
  	int sheetMatchAmount=0;
  	for(int i=0;i<sheetAmount;i++){//遍历sheet
  		if(toWorkbook.getSheetName(i).startsWith("财务报表")){
  			sheetMatchAmount++;
  		}
  	}
  	if(sheetMatchAmount==0){ 
  		toWorkbook.setSheetName(sheetAmount-1, "财务报表_1");
  	}else{ 
  		toWorkbook.setSheetName(sheetAmount-1,"财务报表_"+(sheetMatchAmount+1));
  	}
  	//2.复制源文件sheet框架 
  	POIUtils.copySheet(toWorkbook, fromSheet, toSheet);//调用的还是博文上面的那个工具类
  	//3.根据tableId从数据库中获得数据并封装为map
  	Map<String, Object> paramMap = this.putData(true, tableId);
  	//4.填充数据
  	boolean isData=(boolean)paramMap.get("isData");
      if (isData) {
      	toWorkbook=this.createFile(toWorkbook, toSheet, paramMap);
  	}   
      return toWorkbook;
  }
  
### 合并多个Excel文件一个文件的实现方法 在Java中使用Apache POI库可以有效地处理和操作Excel文件。以下是一个示例,展示如何将多个`.xlsx`格式的Excel文件合并一个文件,并确保低内存消耗[^1]。 #### 依赖配置 首先,确保在项目中添加了Apache POI的依赖: ```xml <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency> ``` #### 示例代码 以下是将多个Excel文件合并一个文件的完整代码: ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class ExcelMerger { public static void mergeExcelFiles(String[] fileNames, String outputFileName) throws IOException { // 使用SXSSFWorkbook以降低内存消耗 try (SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 保留100行在内存中 FileOutputStream outputStream = new FileOutputStream(outputFileName)) { for (String fileName : fileNames) { try (FileInputStream inputStream = new FileInputStream(new File(fileName)); Workbook inputWorkbook = WorkbookFactory.create(inputStream)) { int numberOfSheets = inputWorkbook.getNumberOfSheets(); for (int sheetIndex = 0; sheetIndex < numberOfSheets; sheetIndex++) { Sheet inputSheet = inputWorkbook.getSheetAt(sheetIndex); Sheet outputSheet = workbook.createSheet(inputSheet.getSheetName()); for (Row row : inputSheet) { Row newRow = outputSheet.createRow(row.getRowNum()); for (Cell cell : row) { Cell newCell = newRow.createCell(cell.getColumnIndex()); copyCell(cell, newCell); } } } } } // 将合并后的工作簿写入输出文件 workbook.write(outputStream); } } private static void copyCell(Cell oldCell, Cell newCell) { switch (oldCell.getCellType()) { case STRING: newCell.setCellValue(oldCell.getStringCellValue()); break; case NUMERIC: if (DateUtil.isCellDateFormatted(oldCell)) { newCell.setCellValue(oldCell.getDateCellValue()); } else { newCell.setCellValue(oldCell.getNumericCellValue()); } break; case BOOLEAN: newCell.setCellValue(oldCell.getBooleanCellValue()); break; case FORMULA: newCell.setCellFormula(oldCell.getCellFormula()); break; default: break; } } public static void main(String[] args) { String[] fileNames = {"file1.xlsx", "file2.xlsx", "file3.xlsx"}; String outputFileName = "merged_output.xlsx"; try { mergeExcelFiles(fileNames, outputFileName); System.out.println("Excel files have been merged successfully."); } catch (IOException e) { e.printStackTrace(); } } } ``` #### 代码说明 1. **SXSSFWorkbook**:用于处理大文件,减少内存占用[^1]。 2. **WorkbookFactory**:支持多种Excel文件格式的读取。 3. **copyCell方法**:根据单元格类型复制数据,确保所有数据正确迁移。 ### 注意事项 - 确保所有输入文件均为`.xlsx`格式。 - 如果需要处理更大数据集,可以调整`SXSSFWorkbook`的缓存行数参数。
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值