在处理Excel文件时,我们常会遇到需要将旧版.xls格式转换为新版.xlsx格式的需求。.xlsx格式基于Open XML标准,支持更多行数(104万行 vs 6.5万行)、更丰富的功能,且文件体积更小。本文ZHANID工具网将通过Java代码演示如何使用Apache POI库实现这一转换,并深入解析关键技术点。
一、技术选型:Apache POI核心组件
Apache POI是处理Office文档的权威Java库,其HSSF模块用于操作.xls,XSSF模块用于操作.xlsx。转换过程需同时依赖以下组件:
<!-- Maven依赖 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency>
二、转换流程分步解析
1. 读取.xls文件
使用HSSFWorkbook类加载旧版Excel文件:
try (FileInputStream fis = new FileInputStream("input.xls");
HSSFWorkbook hssfWorkbook = new HSSFWorkbook(fis)) {
// 读取第一个工作表
HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(0);
// ...后续处理
}
2. 创建.xlsx工作簿
通过XSSFWorkbook创建新版工作簿对象:
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(); XSSFSheet xssfSheet = xssfWorkbook.createSheet(hssfSheet.getSheetName());
3. 复制核心内容
需处理单元格内容、样式、合并区域等要素:
3.1 单元格内容复制
for (Row row : hssfSheet) {
XSSFRow xssfRow = xssfSheet.createRow(row.getRowNum());
for (Cell cell : row) {
XSSFCell xssfCell = xssfRow.createCell(cell.getColumnIndex());
// 处理不同数据类型
switch (cell.getCellType()) {
case STRING:
xssfCell.setCellValue(cell.getStringCellValue());
break;
case NUMERIC:
xssfCell.setCellValue(cell.getNumericCellValue());
break;
// 处理其他类型(布尔值、公式等)
}
}
}3.2 样式克隆 需深度复制单元格样式(字体、边框、背景等):
XSSFCellStyle newStyle = xssfWorkbook.createCellStyle(); newStyle.cloneStyleFrom(cell.getCellStyle()); // 仅克隆基础样式 // 需额外处理字体(因样式不包含字体对象) XSSFFont font = xssfWorkbook.createFont(); font.setFontName(cell.getCellStyle().getFontName()); // ...复制其他字体属性 newStyle.setFont(font); xssfCell.setCellStyle(newStyle);
3.3 合并区域处理
for (int i = 0; i < hssfSheet.getNumMergedRegions(); i++) {
CellRangeAddress mergedRegion = hssfSheet.getMergedRegion(i);
xssfSheet.addMergedRegion(mergedRegion);
}4. 处理特殊元素
公式计算:需重新计算公式(
.xlsx使用不同公式引擎)xssfWorkbook.setForceFormulaRecalculation(true);
图片/图表:需使用
Drawing对象单独处理条件格式:通过
XSSFConditionalFormatting复制规则

三、完整转换工具类实现
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import java.io.*;
public class XlsToXlsxConverter {
public static void convert(String inputPath, String outputPath) throws IOException {
try (HSSFWorkbook hssfWorkbook = new HSSFWorkbook(new FileInputStream(inputPath));
XSSFWorkbook xssfWorkbook = new XSSFWorkbook()) {
for (int i = 0; i < hssfWorkbook.getNumberOfSheets(); i++) {
HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(i);
XSSFSheet xssfSheet = xssfWorkbook.createSheet(hssfSheet.getSheetName());
// 复制行和单元格
copyRows(hssfSheet, xssfSheet);
// 复制列宽
for (int col = 0; col < hssfSheet.getRow(0).getLastCellNum(); col++) {
xssfSheet.setColumnWidth(col, hssfSheet.getColumnWidth(col));
}
}
try (FileOutputStream fos = new FileOutputStream(outputPath)) {
xssfWorkbook.write(fos);
}
}
}
private static void copyRows(Sheet srcSheet, Sheet destSheet) {
for (Row srcRow : srcSheet) {
Row destRow = destSheet.createRow(srcRow.getRowNum());
copyCells(srcRow, destRow);
}
}
private static void copyCells(Row srcRow, Row destRow) {
for (Cell srcCell : srcRow) {
Cell destCell = destRow.createCell(srcCell.getColumnIndex());
copyCell(srcCell, destCell);
}
}
private static void copyCell(Cell srcCell, Cell destCell) {
// 复制单元格值和类型
destCell.setCellType(srcCell.getCellType());
switch (srcCell.getCellType()) {
case STRING:
destCell.setCellValue(srcCell.getStringCellValue());
break;
case NUMERIC:
destCell.setCellValue(srcCell.getNumericCellValue());
break;
// 处理其他类型...
}
// 复制样式
CellStyle newStyle = destCell.getSheet().getWorkbook().createCellStyle();
newStyle.cloneStyleFrom(srcCell.getCellStyle());
destCell.setCellStyle(newStyle);
}
}四、性能优化方案
对于大文件(10万行+),需采用以下优化策略:
内存管理:
// 使用SXSSFWorkbook进行流式处理 SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(100); // 保留100行在内存中
分块读取:
hssfWorkbook.getSheetAt(0).setRowSumsBelow(false); // 禁用自动求和
禁用自动计算:
xssfWorkbook.setForceFormulaRecalculation(false);
五、常见问题处理
Q1: 转换后日期格式异常
原因:HSSF和XSSF的日期处理机制不同
解决方案:统一使用
DataFormat对象DataFormat format = xssfWorkbook.createDataFormat(); cellStyle.setDataFormat(format.getFormat("yyyy-mm-dd"));
Q2: 合并单元格失效
确保在复制行之后调用
addMergedRegion使用
CellRangeAddress的精确坐标
Q3: 公式计算结果为0
转换后需手动触发计算:
FormulaEvaluator evaluator = xssfWorkbook.getCreationHelper().createFormulaEvaluator(); evaluator.evaluateAll();
六、验证转换结果
使用以下代码验证关键要素:
// 检查行数和列数 assert xssfSheet.getPhysicalNumberOfRows() == hssfSheet.getPhysicalNumberOfRows(); // 检查单元格值 XSSFCell destCell = xssfSheet.getRow(0).getCell(0); HSSFCell srcCell = hssfSheet.getRow(0).getCell(0); assertEquals(srcCell.getStringCellValue(), destCell.getStringCellValue()); // 检查样式一致性 assertEquals(srcCell.getCellStyle().getFillForegroundColor(), destCell.getCellStyle().getFillForegroundColor());
七、总结与扩展方向
本文提供的转换方案实现了:
基础数据迁移
样式保留
合并区域处理
可扩展方向包括:
添加图片/图表转换
支持条件格式转换
实现批量文件处理
添加进度监控
通过Apache POI的深度定制,可构建企业级Excel转换解决方案,满足金融、报表等领域的复杂需求。实际开发中需特别注意内存管理,避免处理超大文件时发生OOM错误。
本文由@战地网 原创发布。
该文章观点仅代表作者本人,不代表本站立场。本站不承担相关法律责任。
如若转载,请注明出处:https://www.zhanid.com/biancheng/4559.html




















