erryone.这是我遇到的问题。 使用 POI-OOXML 4.1.2 将 xlsx 中的多个工作表页面拆分为仅包含一个工作表页面的多个 xlsx 文件会导致复制时样式不一致。如何解决这个问题呢? 这是源 xlsx 文件: 这是目标 xlsx 文件: 两张图的区别在于填充颜色不同。源图片的预期填充颜色是什么。源图片的第一行和第二行的填充颜色是 RGB HEX F4B7BE,但目标图片的 RGB HEX 是 C6E0B4。他们是不同的。 这是我复制的 cellStyle 代码:
...
targetStyle = (XSSFCellStyle) targetWorkbook.createCellStyle();
targetStyle.cloneStyleFrom(sourceStyle);
copyFont(((XSSFCellStyle) sourceStyle).getFont(), ((XSSFCellStyle) targetStyle).getFont(), targetStyle);
预期的填充颜色是什么是源图片。 我尝试使用以下代码复制样式:
targetStyle.cloneStyleFrom(sourceStyle);
XSSFColor sourceFillForegroundXSSFColor = ((XSSFCellStyle) sourceStyle).getFillForegroundXSSFColor();
XSSFColor sourceFillBackgroundXSSFColor = ((XSSFCellStyle) sourceStyle).getFillBackgroundXSSFColor();
((XSSFCellStyle) targetStyle).setFillForegroundColor(sourceFillForegroundXSSFColor);
((XSSFCellStyle) targetStyle).setFillBackgroundColor(sourceFillBackgroundXSSFColor);
targetStyle.setFillPattern(sourceStyle.getFillPattern());
没成功。 这是我的所有代码如下: `
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ExcelSplitterUtil {
private final static Map<Integer, Map<Integer, CellStyle>> styleCacheLocal = new HashMap<>();
private final static String excelFileType = ".xlsx";
public static void main(String[] args) {
String inputFilePath = "C:\\Users\\15206\\Desktop\\excel_sheet\\test3\\xlsx文件样式测试1.xlsx";
String outputFolderPath = "C:\\Users\\15206\\Desktop\\excel_sheet\\test3\\target\\";
excelSplitter(inputFilePath, outputFolderPath);
}
public static void excelSplitter(String inputFilePath, String outputFolderPath) {
try (FileInputStream fileInputStream = new FileInputStream(inputFilePath)) {
Workbook sourceWorkbook;
if (inputFilePath.endsWith(".xlsx")) {
sourceWorkbook = new XSSFWorkbook(fileInputStream);
} else if (inputFilePath.endsWith(".xls")) {
sourceWorkbook = new HSSFWorkbook(fileInputStream);
} else {
return;
}
for (int sheetIndex = 0; sheetIndex < sourceWorkbook.getNumberOfSheets(); sheetIndex++) {
Workbook targetWorkbook = null;
String sheetName = sourceWorkbook.getSheetAt(sheetIndex).getSheetName();
if (StringUtils.isNoneBlank(excelFileType)) {
if (excelFileType.equals(".xlsx")) {
targetWorkbook = new XSSFWorkbook();
} else if (excelFileType.equals(".xls")) {
targetWorkbook = new HSSFWorkbook();
} else {
//log.error("Unsupported Excel file format: {}", excelFileType);
break;
}
} else {
//throw new BizRuntimeException("ExcelFileType cannot be empty!");
}
//}
Sheet sourceSheet = sourceWorkbook.getSheetAt(sheetIndex);
Sheet targetSheet = targetWorkbook.createSheet(sourceSheet.getSheetName());
copySheet(sourceSheet, targetSheet, sourceWorkbook, targetWorkbook, excelFileType);
String outputFilePath = outputFolderPath + sheetName + excelFileType;
List<String> uploadPaths = new ArrayList<>();
uploadPaths.add(outputFilePath);
if (!new File(outputFilePath).exists()) {
String tempDir = outputFilePath.substring(0, outputFilePath.lastIndexOf(File.separator));
new File(tempDir).mkdirs();
}
try (FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath)) {
targetWorkbook.write(fileOutputStream);
}
targetWorkbook.close();
}
sourceWorkbook.close();
} catch (IOException e) {
} catch (EncryptedDocumentException e) {
}
}
private static void copySheet(Sheet sourceSheet, Sheet targetSheet, Workbook sourceWorkbook, Workbook targetWorkbook, String excelFileType) {
int totalRowNum = sourceSheet.getLastRowNum() - sourceSheet.getFirstRowNum() + 1;
System.out.println("totalRowNum--------------------" + totalRowNum);
for (int rowIndex = 0; rowIndex < totalRowNum; rowIndex++) {
Row sourceRow = sourceSheet.getRow(rowIndex);
Row targetRow = targetSheet.createRow(rowIndex);
if (sourceRow != null) {
// 设置行宽
float sourceRowHeightInPoints = sourceRow.getHeightInPoints();
targetRow.setHeightInPoints(sourceRowHeightInPoints);
int cellNum = sourceRow.getLastCellNum();
System.out.println("cellNum-----------{}----" + cellNum);
for (int colIndex = 0; colIndex < sourceRow.getLastCellNum(); colIndex++) {
Cell sourceCell = sourceRow.getCell(colIndex);
Cell targetCell = targetRow.createCell(colIndex);
if (sourceCell != null) {
// 处理不同数据类型的赋值
setCellValue(targetCell, sourceCell);
// 设置列宽
int columnWidth = sourceSheet.getColumnWidth(colIndex);
// 从第colIndex列开始,该列的宽度是 columnWidth
targetSheet.setColumnWidth(colIndex, columnWidth);
//复制样式
copyCellStyle(sourceCell, targetCell, targetSheet, sourceWorkbook, targetWorkbook, excelFileType);
}
}
}
}
}
private static void copyCellStyle(Cell sourceCell, Cell targetCell, Sheet targetSheet,
Workbook sourceWorkbook, Workbook targetWorkbook, String excelFileType) {
CellStyle sourceStyle = sourceCell.getCellStyle();
CellStyle targetStyle = getOrCreateTargetStyle(sourceStyle, sourceWorkbook, targetWorkbook, excelFileType);
// 将新样式应用于目标单元格
targetCell.setCellStyle(targetStyle);
// 合并单元格信息
CellRangeAddress mergedRegion = findMergedRegion(sourceCell, sourceCell.getSheet());
if (mergedRegion != null && !isMergedRegionOverlapping(mergedRegion, targetSheet)) {
targetCell.getSheet().addMergedRegion(mergedRegion);
}
}
private static CellStyle getOrCreateTargetStyle(CellStyle sourceStyle, Workbook sourceWorkbook, Workbook targetWorkbook, String excelFileType) {
int sourceStyleIndex = sourceStyle.getIndex();
if (styleCacheLocal.containsKey(sourceStyleIndex)) {
Map<Integer, CellStyle> workbookStyles = styleCacheLocal.get(sourceStyleIndex);
return workbookStyles.computeIfAbsent(System.identityHashCode(targetWorkbook), key -> createAndCacheStyle(sourceStyle, sourceWorkbook, targetWorkbook, excelFileType));
} else {
return createAndCacheStyle(sourceStyle, sourceWorkbook, targetWorkbook, excelFileType);
}
}
private static CellStyle createAndCacheStyle(CellStyle sourceStyle, Workbook sourceWorkbook, Workbook targetWorkbook, String excelFileType) {
CellStyle targetStyle = null;
if (excelFileType.equals(".xlsx") && sourceStyle instanceof XSSFCellStyle) {
// 源excel 是 xlsx, 目标是xlsx
targetStyle = (XSSFCellStyle) targetWorkbook.createCellStyle();
// 复制基本的样式属性
targetStyle.cloneStyleFrom(sourceStyle);
//复制字体
copyFont(((XSSFCellStyle) sourceStyle).getFont(), ((XSSFCellStyle) targetStyle).getFont(), targetStyle);
} else if (excelFileType.equals(".xlsx") && sourceStyle instanceof HSSFCellStyle) {
// 源excel 是 xls, 目标是xlsx
targetStyle = (XSSFCellStyle) targetWorkbook.createCellStyle();
// 复制其他样式属性
manualCloneStyle(targetStyle, sourceStyle);
//复制字体
HSSFFont sourceFont = (HSSFFont) sourceWorkbook.getFontAt(sourceStyle.getFontIndexAsInt());
copyFont(sourceFont, ((XSSFCellStyle) targetStyle).getFont(), targetStyle);
} else if (excelFileType.equals(".xls") && sourceStyle instanceof XSSFCellStyle) {
// 源excel 是 xlsx, 目标是xls
targetStyle = (HSSFCellStyle) targetWorkbook.createCellStyle();
// 手动复制不兼容样式
manualCloneStyle(targetStyle, sourceStyle);
//复制字体
copyFont(((XSSFCellStyle) sourceStyle).getFont(), ((HSSFCellStyle) targetStyle).getFont(targetWorkbook), targetStyle);
} else if (excelFileType.equals(".xls") && sourceStyle instanceof HSSFCellStyle) {
// 源excel 是 xls, 目标是xls
targetStyle = (HSSFCellStyle) targetWorkbook.createCellStyle();
// 复制基本的样式属性
targetStyle.cloneStyleFrom(sourceStyle);
//复制字体
copyFont(((HSSFCellStyle) sourceStyle).getFont(sourceWorkbook), ((HSSFCellStyle) targetStyle).getFont(targetWorkbook), targetStyle);
} else {
System.out.println("文件类型excelFileType不匹配");
return null;
}
Map<Integer, CellStyle> workbookStyles = new HashMap<>();
workbookStyles.put(System.identityHashCode(targetWorkbook), targetStyle);
styleCacheLocal.put(Integer.valueOf(sourceStyle.getIndex()), workbookStyles);
return targetStyle;
}
private static void manualCloneStyle(CellStyle targetStyle, CellStyle sourceStyle) {
targetStyle.setAlignment(sourceStyle.getAlignment());
targetStyle.setVerticalAlignment(sourceStyle.getVerticalAlignment());
targetStyle.setWrapText(sourceStyle.getWrapText());
targetStyle.setDataFormat(sourceStyle.getDataFormat());
targetStyle.setFillForegroundColor(sourceStyle.getFillForegroundColor());
targetStyle.setFillBackgroundColor(sourceStyle.getFillBackgroundColor());
targetStyle.setFillPattern(sourceStyle.getFillPattern());
targetStyle.setHidden(sourceStyle.getHidden());
targetStyle.setIndention(sourceStyle.getIndention());
targetStyle.setLocked(sourceStyle.getLocked());
targetStyle.setRotation(sourceStyle.getRotation());
targetStyle.setBorderBottom(sourceStyle.getBorderBottom());
targetStyle.setBorderLeft(sourceStyle.getBorderLeft());
targetStyle.setBorderRight(sourceStyle.getBorderRight());
targetStyle.setBorderTop(sourceStyle.getBorderTop());
targetStyle.setTopBorderColor(sourceStyle.getTopBorderColor());
targetStyle.setBottomBorderColor(sourceStyle.getBottomBorderColor());
targetStyle.setLeftBorderColor(sourceStyle.getLeftBorderColor());
targetStyle.setQuotePrefixed(sourceStyle.getQuotePrefixed());
targetStyle.setShrinkToFit(sourceStyle.getShrinkToFit());
}
private static void copyFont(Font sourceFont, Font targetFont, CellStyle cellStyle) {
targetFont.setFontName(sourceFont.getFontName());
targetFont.setFontHeightInPoints(sourceFont.getFontHeightInPoints());
targetFont.setBold(sourceFont.getBold());
targetFont.setItalic(sourceFont.getItalic());
if (targetFont instanceof XSSFFont) {
if (sourceFont instanceof XSSFFont) {
((XSSFFont) targetFont).setColor(((XSSFFont) sourceFont).getXSSFColor());
} else if (sourceFont instanceof HSSFFont) {
((XSSFFont) targetFont).setColor(sourceFont.getColor());
}
} else {
if (sourceFont instanceof XSSFFont) {
((HSSFFont) targetFont).setColor(sourceFont.getColor());
} else if (sourceFont instanceof HSSFFont) {
((HSSFFont) targetFont).setColor(sourceFont.getColor());
}
}
// 设置新字体到新样式
cellStyle.setFont(targetFont);
}
private static void setCellValue(Cell targetCell, Cell sourceCell) {
switch (sourceCell.getCellType()) {
case STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
case NUMERIC:
if (DateUtil.isCellDateFormatted(sourceCell)) {
targetCell.setCellValue(sourceCell.getDateCellValue());
} else {
targetCell.setCellValue(sourceCell.getNumericCellValue());
}
break;
case BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case FORMULA:
targetCell.setCellFormula(sourceCell.getCellFormula());
break;
default:
targetCell.setCellValue(sourceCell.toString());
break;
}
}
private static boolean isMergedRegionOverlapping(CellRangeAddress newMergedRegion, Sheet targetSheet) {
for (int i = 0; i < targetSheet.getNumMergedRegions(); i++) {
CellRangeAddress existingMergedRegion = targetSheet.getMergedRegion(i);
if (existingMergedRegion.intersects(newMergedRegion)) {
return true;
}
}
return false;
}
private static CellRangeAddress findMergedRegion(Cell cell, Sheet sourceSheet) {
for (int i = 0; i < sourceSheet.getNumMergedRegions(); i++) {
CellRangeAddress merged = sourceSheet.getMergedRegion(i);
if (merged.isInRange(cell.getRowIndex(), cell.getColumnIndex())) {
return merged;
}
}
return null;
}
}
and here is my pom.xml as follow :
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- excel tool -->
<!--xls(03)-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<!--xlsx(07)-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.12.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
</dependencies>
` 刚才我尝试在Excel中设置样式并保存为源文件,然后将文件交给程序来分割并复制样式。结果是目标文件的风格与源文件的风格不一致。我应该如何调整它以使其相同?这是我的源文件和目标文件的屏幕截图。 ;
我感觉这是一个 POI bug!
正如我所说,颜色差异对我来说是无法重现的。至少对于 Office Open XML 格式
*.xlsx
以及使用同一应用程序查看所有内容时不适用。
在不同的应用程序中查看时,差异可能是由于填充颜色是主题颜色,并且一个电子表格应用程序对主题颜色的解释与另一个不同。
但是您的大量代码中可能存在一些问题。或者使用的旧 Apache POI 版本 4.1.2 存在错误。
使用当前的 Apache POI 5.2.5,可以使用以下小代码实现相同的功能:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.util.CellUtil;
public class ExcelSplitterUtil {
public static void excelSplitter(String inputFilePath, String outputFolderPath) {
try ( Workbook sourceWorkbook = WorkbookFactory.create(new FileInputStream(inputFilePath)); ) {
for (Sheet sourceSheet : sourceWorkbook) {
String sourceSheetName = sourceSheet.getSheetName();
Workbook targetWorkbook = null;
String suffix = "";
if (sourceWorkbook instanceof XSSFWorkbook) {
targetWorkbook = new XSSFWorkbook();
suffix = ".xlsx";
} else if (sourceWorkbook instanceof HSSFWorkbook) {
targetWorkbook = new HSSFWorkbook();
suffix = ".xls";
}
Sheet targetSheet = targetWorkbook.createSheet(sourceSheetName);
CellCopyPolicy cellCopyPolicy= new CellCopyPolicy();
CellCopyContext cellCopyContext = new CellCopyContext();
for (Row sourceRow : sourceSheet) {
Row targetRow = targetSheet.createRow(sourceRow.getRowNum());
for (Cell sourceCell : sourceRow) {
Cell targetCell = targetRow.createCell(sourceCell.getColumnIndex());
CellUtil.copyCell(sourceCell, targetCell, cellCopyPolicy, cellCopyContext);
}
}
String outputFilePath = outputFolderPath + sourceSheetName + suffix;
try ( FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath) ) {
targetWorkbook.write(fileOutputStream);
}
targetWorkbook.close();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
//String inputFilePath = "./source.xls"; //file must exist
String inputFilePath = "./source.xlsx"; //file must exist
String outputFolderPath = "./target/"; //path must exist
excelSplitter(inputFilePath, outputFolderPath);
}
}
解决方案是使用 CellUtil.copyCell ,其内部功能与您的大量代码相同。也许升级到 Apache POI 5.2.5 后尝试一下?
使用二进制
*.xls
格式 (HSSF
),使用高于 2007 的 Excel 版本创建 source.xlsx
时会出现颜色差异,并且在保存时会引发兼容性检查警告。这是因为 Apache POI 在引入兼容性检查之前以与旧 Excel 版本相对应的格式创建 *.xls
文件。