如果只需要 写入 Excel 文件 ,使用 XSSFWorkbook 可能会遇到以下问题,尤其是在处理 大数据量(如超过 10 万行) 时:
1. XSSFWorkbook 写入文件的主要问题
(1)内存溢出(OOM)
-
原因 :
XSSFWorkbook会将 整个 Excel 文件(包括所有行、单元格、样式等) 全部加载到内存中。 -
表现 :
- 如果数据量较大(如 10 万行以上),JVM 内存可能不足,抛出
OutOfMemoryError。 - 即使不报 OOM,内存占用也会非常高,影响系统性能。
- 如果数据量较大(如 10 万行以上),JVM 内存可能不足,抛出
-
示例 :
java`XSSFWorkbook workbook = new XSSFWorkbook(); // 创建空工作簿 XSSFSheet sheet = workbook.createSheet("Sheet1"); // 写入 100 万行数据(内存爆炸!) for (int i = 0; i < 1_000_000; i++) { XSSFRow row = sheet.createRow(i); row.createCell(0).setCellValue("Data " + i); } // 保存到文件(可能 OOM) try (FileOutputStream fos = new FileOutputStream("output.xlsx")) { workbook.write(fos); }`- 结果:JVM 内存耗尽,程序崩溃。
(2)性能问题
- 写入速度慢 :
XSSFWorkbook在内存中构建整个 Excel 结构,数据量大时 构建时间极长。- 调用
workbook.write()时,所有数据一次性写入磁盘,I/O 压力大。
- GC 压力 :
- 大数据量会导致 频繁 GC(垃圾回收),进一步降低性能。
2. 替代方案:SXSSFWorkbook(推荐)
(1)为什么 SXSSFWorkbook 更适合写入大数据?
- 流式写入(Streaming API) :
- 仅保留 最近 N 行 (默认 100 行)在内存中,其余数据 直接写入磁盘临时文件。
- 用 磁盘空间换内存空间,避免 OOM。
- 内存占用低 :
- 即使写入 100 万行数据,内存占用也几乎不变(仅保留最新几行)。
- 性能更好 :
- 数据逐行写入磁盘,减少内存压力和 GC 开销。
(2)SXSSFWorkbook 写入示例
java
`// 1. 创建 SXSSFWorkbook(保留 100 行在内存)
SXSSFWorkbook workbook = new SXSSFWorkbook(100);
SXSSFSheet sheet = workbook.createSheet("Sheet1");
// 2. 写入 100 万行数据(不会 OOM)
for (int i = 0; i < 1_000_000; i++) {
SXSSFRow row = sheet.createRow(i);
row.createCell(0).setCellValue("Data " + i);
// 可选:手动刷新行到磁盘(减少内存占用)
if (i % 1000 == 0) {
((SXSSFSheet) sheet).flushRows(100); // 保留最近 100 行
}
}
// 3. 保存到文件
try (FileOutputStream fos = new FileOutputStream("output.xlsx")) {
workbook.write(fos);
}
// 4. 清理临时文件(必须调用!)
workbook.dispose();`
- 关键点 :
new SXSSFWorkbook(100):内存中保留 100 行,其余写入磁盘。flushRows(100):手动刷新行到磁盘(可选)。dispose():删除临时文件(必须调用,否则磁盘可能残留垃圾文件)。
3. 其他替代方案
(1)EasyExcel(阿里开源)
-
优点 :
- 基于 SAX 模式解析 Excel,几乎无内存限制。
- API 简单,支持大数据量写入。
-
示例 :
java`// 1. 定义数据模型 public class DemoData { @ExcelProperty("数据") private String data; // getters & setters } // 2. 写入 Excel List<DemoData> dataList = new ArrayList<>(); for (int i = 0; i < 1_000_000; i++) { dataList.add(new DemoData("Data " + i)); } EasyExcel.write("output.xlsx", DemoData.class) .sheet("Sheet1") .doWrite(dataList);` -
适用场景 :
- 需要 极低内存占用 的大数据量写入。
- 项目允许引入第三方库。
(2)CSV 格式(如果不需要 Excel 特性)
-
优点 :
- 纯文本格式,无内存问题。
- 写入速度极快。
-
示例 :
java`try (PrintWriter pw = new PrintWriter(new FileWriter("output.csv"))) { for (int i = 0; i < 1_000_000; i++) { pw.println("Data " + i); } }` -
适用场景 :
- 不需要 Excel 格式(如公式、样式、多 Sheet 等)。
- 仅需存储结构化数据。
4. 总结
| 方案 | 内存占用 | 性能 | 适用场景 |
|---|---|---|---|
XSSFWorkbook |
❌ 高(OOM 风险) | ❌ 慢 | 小数据量(< 10 万行) |
SXSSFWorkbook |
✅ 低 | ✅ 快 | 大数据量(> 10 万行) |
EasyExcel |
✅ 极低 | ✅ 极快 | 大数据量 + 需要 Excel 格式 |
CSV |
✅ 极低 | ✅ 极快 | 不需要 Excel 特性 |
推荐选择
- 如果必须用 POI →
SXSSFWorkbook(流式写入,避免 OOM)。 - 如果项目允许第三方库 →
EasyExcel(更简单、更高效)。 - 如果不需要 Excel 特性 →
CSV(最快、最省内存)。
⚠️ 绝对不要用 XSSFWorkbook 写入大数据! 否则必然面临 OOM 或性能崩溃问题。