项目动机是因为公司在系统下载的Excel表格太零散,需要整合成一个Excel文件分成里面的多个工作表,这里就需要将所有Excel文件读取出来后原封不动的搬到新的Excel文件内。
不可避免的就会涉及到Excel的嵌入式图片和浮动图片的设置操作。
这里我直接封装了方法,先看效果。
package com.gsr.Excel;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressBase;
import org.apache.poi.xssf.usermodel.*;
import java.io.*;
import java.util.List;
/**
* 将多个Excel文件合并为一个Excel文件
* 变成多个excel工作簿
*/
public class MergeExcelFilesExample {
public static void main(String[] args) throws Exception {
// 创建新的工作簿
Workbook mergedWorkbook = new XSSFWorkbook();
// 读取第一个Excel文件
String filePath1 = "C:\\Users\\阿辉\\Desktop\\国家模板2.0_France-法国_20231215152652A076.xlsx";
FileInputStream fileIn1 = new FileInputStream(filePath1);
Workbook workbook1 = WorkbookFactory.create(fileIn1);
// 将第一个Excel文件的工作表复制到合并的工作簿中
copySheets(workbook1, mergedWorkbook);
// 读取第二个Excel文件
String filePath2 = "C:\\Users\\阿辉\\Desktop\\报销和资产购买模板V2.0_通用_20231114_20231215140918A070.xlsx";
FileInputStream fileIn2 = new FileInputStream(filePath2);
Workbook workbook2 = WorkbookFactory.create(fileIn2);
// 将第二个Excel文件的工作表复制到合并的工作簿中
copySheets(workbook2, mergedWorkbook);
// 保存合并后的工作簿到文件
String mergedFilePath = "C:\\Users\\阿辉\\Desktop\\合并后的文件.xlsx";
FileOutputStream fileOut = new FileOutputStream(mergedFilePath);
mergedWorkbook.write(fileOut);
fileOut.close();
// 关闭资源
workbook1.close();
workbook2.close();
fileIn1.close();
fileIn2.close();
System.out.println("Excel文件合并完成!");
}
/**
* 复制工作表到目标工作簿中
* @param sourceWorkbook 源工作簿
* @param targetWorkbook 目标工作簿
*/
private static void copySheets(Workbook sourceWorkbook, Workbook targetWorkbook) {
for (int i = 0; i < sourceWorkbook.getNumberOfSheets(); i++) {
Sheet sourceSheet = sourceWorkbook.getSheetAt(i);
String sheetName = sourceSheet.getSheetName();
Sheet targetSheet = targetWorkbook.createSheet(sheetName);
targetWorkbook.setSheetOrder(sheetName, i);
// 复制源工作表中的每一行
for (Row sourceRow : sourceSheet) {
Row targetRow = targetSheet.createRow(sourceRow.getRowNum());
// 复制源行中的每个单元格
for (Cell sourceCell : sourceRow) {
Cell targetCell = targetRow.createCell(sourceCell.getColumnIndex(), sourceCell.getCellType());
// 将单元格的值复制到目标单元格
switch (sourceCell.getCellType()) {
case STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
case NUMERIC:
targetCell.setCellValue(sourceCell.getNumericCellValue());
break;
case BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case FORMULA:
targetCell.setCellFormula(sourceCell.getCellFormula());
break;
default:
// 处理其他类型的单元格
}
// 复制单元格样式和属性
CellStyle sourceCellStyle = sourceCell.getCellStyle();
CellStyle targetCellStyle = targetWorkbook.createCellStyle();
targetCellStyle.cloneStyleFrom(sourceCellStyle);
targetCell.setCellStyle(targetCellStyle);
//复制单元格大小
targetSheet.setColumnWidth(targetCell.getColumnIndex(), sourceSheet.getColumnWidth(sourceCell.getColumnIndex()));
targetSheet.setColumnHidden(targetCell.getColumnIndex(), sourceSheet.isColumnHidden(sourceCell.getColumnIndex()));
}
}
// 复制单元格合并状态
for (CellRangeAddress mergedRegion : sourceSheet.getMergedRegions()) {
targetSheet.addMergedRegion(mergedRegion);
}
//将源工作表的所有图片复制到目标工作表中
copyingExcelImagesAll(sourceWorkbook, targetWorkbook, targetSheet);
}
}
/**
* 将源工作表的所有图片复制到目标工作表中
* @param sourceWorkbook 源工作簿
* @param targetWorkbook 目标工作簿
* @param targetSheet 目标工作表
*/
private static void copyingExcelImagesAll(Workbook sourceWorkbook, Workbook targetWorkbook, Sheet targetSheet) {
// 获取源工作表的所有图片对象
List<? extends PictureData> allPictures = sourceWorkbook.getAllPictures();
// 遍历所有图片数据
allPictures.forEach(pictureData -> {
// 获取图片转成bate数组,获取图片格式
byte[] data = pictureData.getData();
int pictureType = pictureData.getPictureType();
int pictureIndex = targetWorkbook.addPicture(data, pictureType);
// 目标excel 创建绘图锚点,设置图片位置和大小
CreationHelper creationHelper = targetWorkbook.getCreationHelper();
ClientAnchor clientAnchor = creationHelper.createClientAnchor();
//修改图片位置和大小(设置四条边框,图片自动填满整个指定的位置)
clientAnchor.setCol1(0); // 左上角的列位置
clientAnchor.setRow1(0); // 左上角的行位置
clientAnchor.setCol2(1); // 右下角的列位置
clientAnchor.setRow2(1); // 右下角的行位置
// 创建绘图对象并添加到目标工作表
Drawing<?> drawingPatriarch = targetSheet.createDrawingPatriarch();
drawingPatriarch.createPicture(clientAnchor, pictureIndex);
});
}
}
设置图片
浮动在Java POI中,我们可以通过HSSFPicture类来表示Excel中的图片,通过ClientAnchor类来设置图片的浮动属性。
首先,我们需要创建一个HSSFWorkbook对象来表示Excel工作簿,然后创建一个Sheet对象来表示工作表。
设置图片浮动在Java POI中,我们可以通过HSSFPicture类来表示Excel中的图片,通过ClientAnchor类来设置图片的浮动属性。首先,我们需要创建一个HSSFWorkbook对象来表示Excel工作簿,然后创建一个 Sheet对象来表示工作表。
HSSFWorkbook workbook = new HSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet1");
接下来,我们可以使用 FileInputStream 或者 ByteArrayInputStream 来读取图片文件,并使用 Workbook 的 addPicture 方法将图片添加到工作簿中。
/** 注意:这是演示代码,我上面封装方法这里的类型是直接获取了源工作表的图片类型和图片 */
InputStream inputStream = new FileInputStream("path/to/image.jpg");
byte[] bytes = IOUtils.toByteArray(inputStream);
int pictureIndex = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
然后,我们可以使用 CreationHelper 的 createClientAnchor 方法创建一个 ClientAnchor 对象,并设置图片的浮动属性。
CreationHelper helper = workbook.getCreationHelper();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(0); // 图片左上角所在列的索引
anchor.setRow1(0); // 图片左上角所在行的索引
anchor.setCol2(5); // 图片右下角所在列的索引
anchor.setRow2(5); // 图片右下角所在行的索引
最后,我们可以使用 Drawing 对象的 createPicture 方法将图片插入到工作表中,并设置图片的 ClientAnchor。
Drawing<?> drawing = sheet.createDrawingPatriarch();
Picture picture = drawing.createPicture(anchor, pictureIndex);
最后我还找到了一个图,可以更好的理解设置图片的层级关系。
水完收工~~~~~~~~~~~~~
下次更新可根据用户自由匹配的Excel模板识别工具,还在整理需求,大家有啥好建议欢迎大家柳岩哈哈哈!