当前位置: 代码网 > it编程>编程语言>Java > Java使用FileOutputStream写Excel文件不落盘的解决方法

Java使用FileOutputStream写Excel文件不落盘的解决方法

2025年11月03日 Java 我要评论
引言最近在写 java 代码处理 excel 文件的时候,遇到了一个挺头疼的问题:使用 apache poi 的 xssfworkbook.write(fileoutputstream) 方法写文件,

引言

最近在写 java 代码处理 excel 文件的时候,遇到了一个挺头疼的问题:使用 apache poi 的 xssfworkbook.write(fileoutputstream) 方法写文件,代码执行得好好的,也没有抛出异常,但生成的 excel 文件却打不开,甚至有时候文件大小还是 0 字节,一点数据都没有。

本来以为是 poi 的问题,结果查了一圈文档才发现——锅还真不在 poi,而是我自己对文件输出流的使用方式不太对,尤其是涉及到 fileoutputstream 的时候,有些隐藏的“坑”没注意到。

这篇文章就把我踩坑的过程整理一下,顺便聊聊 java 中如何正确地使用输出流写 excel 文件,避免“写了但没落盘”的问题。

1. fileoutputstream 本身是没有缓冲

我们先来看看一个最常见的代码片段:

workbook workbook = new xssfworkbook(inputstream);
workbook.write(new fileoutputstream("output.xlsx"));

这样写看起来挺顺,但你知道吗?这里的 fileoutputstream 直接把数据写到操作系统的,没有中间的缓冲区。如果你的数据量很大,比如几百 kb,甚至几 mb,虽然代码没报错,但你可能会发现文件根本没写完整,或者干脆就是个空壳文件。

为什么?

因为操作系统本身还会有一个写入缓冲区(page cache),你并不能保证调用了 write() 之后,数据就马上稳稳当当地落到了磁盘上。如果你没有关闭输出流或者手动调用 flush(),这些数据可能就一直在内存里排队,根本没真正写进文件。

2. 没有 flush() 或 close(),数据可能永远不会写进硬盘

这是很多人常犯的一个错误。看上去代码没问题,但一旦你漏掉了 flush() 或者 close(),就会导致写入的数据停留在缓冲区里,始终不落盘。

比如下面这段代码就是“反面教材”:

fileoutputstream fos = new fileoutputstream("output.xlsx");
workbook.write(fos);
// 没有 fos.flush()
// 没有 fos.close()

你以为 write() 就完事了,其实根本没有。解决方案很简单,要么在写完之后手动调用:

fos.flush();
fos.close();

要么——更推荐的方式是使用 try-with-resources 来自动帮你处理这些关闭操作。

3. 用 bufferedoutputstream 包装一下,写得更稳也更快

前面说了,fileoutputstream 是没有缓冲的,这意味着它每调用一次 write() 就是一次底层系统调用,效率其实挺低的,尤其是在 apache poi 这种写 excel 文件会反复调用 write() 的场景下。

所以非常推荐你用 bufferedoutputstream 包一下:

outputstream bos = new bufferedoutputstream(new fileoutputstream("output.xlsx"));
workbook.write(bos);
bos.flush();
bos.close();

多一层缓冲不仅能提升写入速度,更重要的是减少系统调用的频率,能让写入过程更加稳定可靠。

4. 推荐用法:try-with-resources,优雅又安全

说了这么多,其实最靠谱、最简单、最不容易出错的写法,还是 java 7 引入的 try-with-resources。

你只要这么写:

try (
    inputstream inputstream = new fileinputstream("template.xlsx");
    workbook workbook = new xssfworkbook(inputstream);
    outputstream outputstream = new bufferedoutputstream(new fileoutputstream("output.xlsx"))
) {
    workbook.write(outputstream);
}

java 会自动帮你在块结束后关闭 inputstream、workbook 和 outputstream,再也不用担心忘了 flush()close() 了,简直不要太爽。

5. 如果你就是不想用 try-with-resources,也请手动关闭资源

当然,也不是所有项目都能用上 java 7 及以上版本的语法,博主前些时间就接到了一个java 6的项目咨询,还真不是,你发任你发,我用java 8。哈哈,有些老项目没法用 try-with-resources。那也不是不能写,你只要自己负责把所有资源都在 finally 中手动关闭,也一样可以稳稳落盘。

注意关闭的顺序要搞对,先关 workbook,再关输出流。

示例如下:

workbook workbook = null;
bufferedoutputstream bos = null;
 
try {
    workbook = new xssfworkbook();
    bos = new bufferedoutputstream(new fileoutputstream("output.xlsx"));
 
    workbook.write(bos);
    bos.flush();
 
} catch (exception e) {
    e.printstacktrace();
} finally {
    try {
        if (workbook != null) workbook.close();
        if (bos != null) bos.close(); // close 会自动 flush
    } catch (ioexception e) {
        e.printstacktrace();
    }
}

记住:close() 会自动调用 flush(),但你也可以显式加一遍 flush(),确保保险。

大 excel 文件时内存溢出风险

  • xssfworkbook 加载整个 .xlsx 到内存;
  • 写入也可能消耗大量内存;
  • 超过几十万行时可能抛出 oom。

大数据量推荐使用 sxssfworkbook:

sxssfworkbook sxssfworkbook = new sxssfworkbook((xssfworkbook) workbook); 
sxssfworkbook.write(outputstream);
sxssfworkbook.dispose(); // 清理临时文件

6. 工作簿数据本身也别忘了检查

最后还有一个冷门但真实的情况是——你其实根本就没有往 workbook 里写任何东西。这样写出来的 excel 文件虽然也是合法的 .xlsx,但打开后是空白页,或者打开报错,看上去像是“没写进去”,其实是你没写进去数据……

你可以加个调试代码确认:

log.info("sheet count: {}", workbook.getnumberofsheets());

7. 防止“写了但没落盘”的几点 checklist

检查项建议
使用缓冲流bufferedoutputstream 性能更稳
手动或自动关闭flush() + close 必不可少
优先使用 try-with-resources推荐写法,防忘关
大文件用 sxssfworkbook防止内存溢出
确认实际写入数据不要生成空文件

以上就是java使用fileoutputstream写excel文件不落盘的解决方法的详细内容,更多关于java fileoutputstream写excel文件的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com