Java实现XLS转换为XLSX的示例代码详解

原创 2025-06-09 10:03:44编程技术
686

在处理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复制规则

java.webp

三、完整转换工具类实现

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万行+),需采用以下优化策略:

  1. 内存管理

    // 使用SXSSFWorkbook进行流式处理
    SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(100); // 保留100行在内存中
  2. 分块读取

    hssfWorkbook.getSheetAt(0).setRowSumsBelow(false); // 禁用自动求和
  3. 禁用自动计算

    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());

七、总结与扩展方向

本文提供的转换方案实现了:

  • 基础数据迁移

  • 样式保留

  • 合并区域处理

可扩展方向包括:

  1. 添加图片/图表转换

  2. 支持条件格式转换

  3. 实现批量文件处理

  4. 添加进度监控

通过Apache POI的深度定制,可构建企业级Excel转换解决方案,满足金融、报表等领域的复杂需求。实际开发中需特别注意内存管理,避免处理超大文件时发生OOM错误。

Java xls转xlsx
THE END
战地网
频繁记录吧,生活的本意是开心

相关推荐

JavaDB怎么进不去了?3个常见原因和解决办法
问题出在哪?先查连接状态 JavaDB进不去,最常见的就是服务没跑起来。你看,JavaDB默认用1527端口监听。如果连不上,大概率是它没启动或者端口被占了。用这段代码快速检测:...
2026-04-02 新闻资讯
260

Java版连锁挖矿mod叫什么名字
主流连锁挖矿mod名字汇总 根据抖音和百度贴吧的玩家反馈,Java版《我的世界》连锁挖矿mod有好几个常用名字。最常被推荐的是FTB Ultimine。它在抖音多个视频里被提到,能一...
2026-04-02 新闻资讯
416

Java日志管理框架:Log4j、SLF4J、Logback对比与使用方法详解
java主流日志框架中,Log4j 1.x作为早期标准,Log4j 2.x通过重构实现性能飞跃,Logback作为Log4j的继承者以原生SLF4J支持成为主流选择,而SLF4J作为日志门面,通过抽象层实现...
2025-09-15 编程技术
1032

Java 与 MySQL 性能优化:MySQL全文检索查询优化实践
本文聚焦Java与MySQL协同环境下的全文检索优化实践,从索引策略、查询调优、参数配置到Java层优化,深入解析如何释放全文检索的潜力,为高并发、大数据量场景提供稳定高效的搜...
2025-09-13 编程技术
1001

JavaScript 中 instanceof 的作用及使用方法详解
在 JavaScript 的类型检查体系中,instanceof 是一个重要的操作符,用于判断一个对象是否属于某个构造函数的实例或其原型链上的类型。本文ZHANID工具网将系统讲解 instanceof...
2025-09-11 编程技术
1089

Java与MySQL数据库连接实战:JDBC使用教程
JDBC(Java Database Connectivity)作为Java标准API,为开发者提供了统一的数据访问接口,使得Java程序能够无缝连接各类关系型数据库。本文ZHANID工具网将以MySQL数据库为例...
2025-09-11 编程技术
892