最常用、最强大的库是 Apache POI,下面我将详细介绍如何使用 Apache POI 来完成这个任务,并提供几种不同的场景示例。

准备工作:添加 Apache POI 依赖
你需要在你的项目中添加 Apache POI 的依赖,如果你使用 Maven,请在 pom.xml 文件中添加以下内容:
<dependencies>
<!-- Apache POI 核心库 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.5</version> <!-- 建议使用较新版本 -->
</dependency>
<!-- Apache POI OOXML 库,用于处理 .xlsx 格式 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
<!-- 为了更好的性能,建议添加这个依赖 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.2.5</version>
</dependency>
</dependencies>
如果你使用 Gradle,则在 build.gradle 文件中添加:
implementation 'org.apache.poi:poi:5.2.5' implementation 'org.apache.poi:poi-ooxml:5.2.5' implementation 'org.apache.poi:poi-scratchpad:5.2.5'
核心步骤
无论进行何种操作,基本流程都遵循以下三步:
- 读取:使用
XSSFWorkbook打开源 XLSX 文件。 - 处理:遍历工作表、行和单元格,读取数据,进行修改或计算。
- 写入:将修改后的
XSSFWorkbook对象写入到一个新的 XLSX 文件中。
重要:请务必使用 try-with-resources 语句来管理文件流,确保资源被正确关闭。

示例 1:最简单的复制(不修改内容)
这个示例演示了如何将 source.xlsx 完整地复制到 target.xlsx,虽然简单,但它展示了基本框架。
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class SimpleCopyXlsx {
public static void main(String[] args) {
String sourceFilePath = "path/to/your/source.xlsx";
String targetFilePath = "path/to/your/target.xlsx";
try (FileInputStream fis = new FileInputStream(sourceFilePath);
XSSFWorkbook sourceWorkbook = new XSSFWorkbook(fis);
FileOutputStream fos = new FileOutputStream(targetFilePath)) {
// XSSFWorkbook 对象已经包含了源文件的所有内容
// 直接将其写入到新的文件输出流中
sourceWorkbook.write(fos);
System.out.println("文件已成功从 " + sourceFilePath + " 复制到 " + targetFilePath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例 2:修改内容后转换(常见场景)
这是最常见的用法,我们读取一个文件,修改一些数据,然后保存为新文件。
场景:将 students.xlsx 中所有学生的“数学”成绩加 10 分,然后保存为 updated_students.xlsx。
假设 students.xlsx 内容如下:

| 姓名 | 数学 | 英语 |
|---|---|---|
| 张三 | 85 | 90 |
| 李四 | 72 | 88 |
| 王五 | 93 | 95 |
Java 代码实现:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ModifyAndConvertXlsx {
public static void main(String[] args) {
String sourcePath = "students.xlsx";
String targetPath = "updated_students.xlsx";
try (FileInputStream fis = new FileInputStream(sourcePath);
XSSFWorkbook workbook = new XSSFWorkbook(fis);
FileOutputStream fos = new FileOutputStream(targetPath)) {
// 1. 获取第一个工作表
Sheet sheet = workbook.getSheetAt(0);
// 2. 遍历每一行(从第二行开始,假设第一行是标题)
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row == null) {
continue; // 如果某行是空的,则跳过
}
// 3. 获取“数学”成绩所在的单元格(假设它在第二列,索引为1)
Cell mathCell = row.getCell(1); // 列索引从0开始
// 4. 检查单元格是否为数字类型
if (mathCell != null && mathCell.getCellType() == CellType.NUMERIC) {
double originalScore = mathCell.getNumericCellValue();
// 修改值:加10分
mathCell.setCellValue(originalScore + 10);
}
}
// 5. 将修改后的工作簿写入新文件
workbook.write(fos);
System.out.println("文件已处理并成功保存到: " + targetPath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行后的 updated_students.xlsx
| 姓名 | 数学 | 英语 |
|---|---|---|
| 张三 | 95 | 90 |
| 李四 | 82 | 88 |
| 王五 | 103 | 95 |
示例 3:更复杂的操作(添加公式、样式等)
Apache POI 功能非常强大,你还可以进行更复杂的操作。
场景:在 students.xlsx 的末尾添加一个“总分”列,并计算每个学生的总分,为总分高于 180 的学生所在行设置背景色为浅绿色。
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.IndexedColors;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ComplexOperationXlsx {
public static void main(String[] args) {
String sourcePath = "students.xlsx";
String targetPath = "students_with_total.xlsx";
try (FileInputStream fis = new FileInputStream(sourcePath);
XSSFWorkbook workbook = new XSSFWorkbook(fis);
FileOutputStream fos = new FileOutputStream(targetPath)) {
Sheet sheet = workbook.getSheetAt(0);
// 创建单元格样式
CellStyle highScoreStyle = workbook.createCellStyle();
highScoreStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex());
highScoreStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 添加“总分”标题行
Row titleRow = sheet.getRow(0);
if (titleRow == null) {
titleRow = sheet.createRow(0);
}
Cell totalTitleCell = titleRow.createCell(3); // 第四列
totalTitleCell.setCellValue("总分");
// 遍历数据行,计算总分并设置样式
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row == null) continue;
Cell mathCell = row.getCell(1);
Cell englishCell = row.getCell(2);
double math = 0, english = 0;
if (mathCell != null && mathCell.getCellType() == CellType.NUMERIC) {
math = mathCell.getNumericCellValue();
}
if (englishCell != null && englishCell.getCellType() == CellType.NUMERIC) {
english = englishCell.getNumericCellValue();
}
double total = math + english;
Cell totalCell = row.createCell(3); // 在第四列创建总分单元格
totalCell.setCellValue(total);
// 如果总分大于180,应用样式
if (total > 180) {
row.setRowStyle(highScoreStyle); // 为整行设置样式
}
}
workbook.write(fos);
System.out.println("复杂操作完成,文件已保存到: " + targetPath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
性能优化建议
对于处理非常大的 XLSX 文件(包含数万行数据),XSSFWorkbook 会将整个文件加载到内存中,可能导致 OutOfMemoryError。
为了解决这个问题,Apache POI 提供了 SXSSF (Streaming Usermodel API),它是一个基于事件的、低内存占用的 API,非常适合处理大数据量。
SXSSF 的核心思想:
- 它只保留一定数量的“滑动窗口”中的行在内存中。
- 超出窗口的行会被临时写入到磁盘上的临时文件中。
- 所有数据会合并成一个完整的 XLSX 文件。
使用 SXSSF 的示例(概念性):
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFCell;
// ... (省略文件流操作)
// 使用 SXSSFWorkbook 而不是 XSSFWorkbook
// 参数 100 是指在内存中保留100行
try (SXSSFWorkbook workbook = new SXSSFWorkbook(100)) {
SXSSFSheet sheet = workbook.createSheet("Sheet1");
// 创建数据...
for (int i = 0; i < 100000; i++) {
SXSSFRow row = sheet.createRow(i);
SXSSFCell cell = row.createCell(0);
cell.setCellValue("Row " + i);
}
// 写入文件
try (FileOutputStream out = new FileOutputStream("large_file.xlsx")) {
workbook.write(out);
}
// 清理临时文件(非常重要!)
((SXSSFWorkbook) workbook).dispose();
}
注意:SXSSF 有一些限制,例如不能随机访问行(只能顺序写入),并且不能修改已写入磁盘的行,但对于从零开始创建或顺序转换大文件的场景,它是最佳选择。
| 需求场景 | 推荐库 | 特点 |
|---|---|---|
| 小/中型文件,需要读取、修改、再写入 | XSSFWorkbook |
功能最全,可以随机读写任何单元格,但内存占用高。 |
| 大型文件(10万+行),顺序写入或转换 | SXSSFWorkbook |
低内存占用,流式处理,速度快,但只能顺序写入,不能修改。 |
| 仅读取大型文件内容 | XSSF + Event API |
内存占用极低,但使用起来比 Usermodel API 复杂。 |
对于“xlsx 转 xlsx”这个通用问题,XSSFWorkbook 是最常用和最灵活的解决方案,如果你的文件特别大,再考虑使用 SXSSFWorkbook。
