最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用FileOutputStream寫(xiě)Excel文件不落盤(pán)的解決方法

 更新時(shí)間:2025年11月03日 09:21:47   投稿:bairu  
最近在寫(xiě) Java 代碼處理 Excel 文件的時(shí)候,遇到了一個(gè)挺頭疼的問(wèn)題:使用 Apache POI 的 XSSFWorkbook.write(FileOutputStream) 方法寫(xiě)文件,生成的 Excel 文件卻打不開(kāi),所以本文就給大家介紹了Java使用FileOutputStream寫(xiě)Excel文件不落盤(pán)的解決方法

引言

最近在寫(xiě) Java 代碼處理 Excel 文件的時(shí)候,遇到了一個(gè)挺頭疼的問(wèn)題:使用 Apache POI 的 XSSFWorkbook.write(FileOutputStream) 方法寫(xiě)文件,代碼執(zhí)行得好好的,也沒(méi)有拋出異常,但生成的 Excel 文件卻打不開(kāi),甚至有時(shí)候文件大小還是 0 字節(jié),一點(diǎn)數(shù)據(jù)都沒(méi)有。

本來(lái)以為是 POI 的問(wèn)題,結(jié)果查了一圈文檔才發(fā)現(xiàn)——鍋還真不在 POI,而是我自己對(duì)文件輸出流的使用方式不太對(duì),尤其是涉及到 FileOutputStream 的時(shí)候,有些隱藏的“坑”沒(méi)注意到。

這篇文章就把我踩坑的過(guò)程整理一下,順便聊聊 Java 中如何正確地使用輸出流寫(xiě) Excel 文件,避免“寫(xiě)了但沒(méi)落盤(pán)”的問(wèn)題。

1. FileOutputStream 本身是沒(méi)有緩沖

我們先來(lái)看看一個(gè)最常見(jiàn)的代碼片段:

Workbook workbook = new XSSFWorkbook(inputStream);
workbook.write(new FileOutputStream("output.xlsx"));

這樣寫(xiě)看起來(lái)挺順,但你知道嗎?這里的 FileOutputStream 直接把數(shù)據(jù)寫(xiě)到操作系統(tǒng)的,沒(méi)有中間的緩沖區(qū)。如果你的數(shù)據(jù)量很大,比如幾百 KB,甚至幾 MB,雖然代碼沒(méi)報(bào)錯(cuò),但你可能會(huì)發(fā)現(xiàn)文件根本沒(méi)寫(xiě)完整,或者干脆就是個(gè)空殼文件。

為什么?

因?yàn)椴僮飨到y(tǒng)本身還會(huì)有一個(gè)寫(xiě)入緩沖區(qū)(Page Cache),你并不能保證調(diào)用了 write() 之后,數(shù)據(jù)就馬上穩(wěn)穩(wěn)當(dāng)當(dāng)?shù)芈涞搅舜疟P(pán)上。如果你沒(méi)有關(guān)閉輸出流或者手動(dòng)調(diào)用 flush(),這些數(shù)據(jù)可能就一直在內(nèi)存里排隊(duì),根本沒(méi)真正寫(xiě)進(jìn)文件。

2. 沒(méi)有 flush() 或 close(),數(shù)據(jù)可能永遠(yuǎn)不會(huì)寫(xiě)進(jìn)硬盤(pán)

這是很多人常犯的一個(gè)錯(cuò)誤。看上去代碼沒(méi)問(wèn)題,但一旦你漏掉了 flush() 或者 close(),就會(huì)導(dǎo)致寫(xiě)入的數(shù)據(jù)停留在緩沖區(qū)里,始終不落盤(pán)。

比如下面這段代碼就是“反面教材”:

FileOutputStream fos = new FileOutputStream("output.xlsx");
workbook.write(fos);
// 沒(méi)有 fos.flush()
// 沒(méi)有 fos.close()

你以為 write() 就完事了,其實(shí)根本沒(méi)有。解決方案很簡(jiǎn)單,要么在寫(xiě)完之后手動(dòng)調(diào)用:

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

要么——更推薦的方式是使用 try-with-resources 來(lái)自動(dòng)幫你處理這些關(guān)閉操作。

3. 用 BufferedOutputStream 包裝一下,寫(xiě)得更穩(wěn)也更快

前面說(shuō)了,F(xiàn)ileOutputStream 是沒(méi)有緩沖的,這意味著它每調(diào)用一次 write() 就是一次底層系統(tǒng)調(diào)用,效率其實(shí)挺低的,尤其是在 Apache POI 這種寫(xiě) Excel 文件會(huì)反復(fù)調(diào)用 write() 的場(chǎng)景下。

所以非常推薦你用 BufferedOutputStream 包一下:

OutputStream bos = new BufferedOutputStream(new FileOutputStream("output.xlsx"));
workbook.write(bos);
bos.flush();
bos.close();

多一層緩沖不僅能提升寫(xiě)入速度,更重要的是減少系統(tǒng)調(diào)用的頻率,能讓寫(xiě)入過(guò)程更加穩(wěn)定可靠。

4. 推薦用法:try-with-resources,優(yōu)雅又安全

說(shuō)了這么多,其實(shí)最靠譜、最簡(jiǎn)單、最不容易出錯(cuò)的寫(xiě)法,還是 Java 7 引入的 try-with-resources。

你只要這么寫(xiě):

try (
    InputStream inputStream = new FileInputStream("template.xlsx");
    Workbook workbook = new XSSFWorkbook(inputStream);
    OutputStream outputStream = new BufferedOutputStream(new FileOutputStream("output.xlsx"))
) {
    workbook.write(outputStream);
}

Java 會(huì)自動(dòng)幫你在塊結(jié)束后關(guān)閉 inputStream、workbook 和 outputStream,再也不用擔(dān)心忘了 flush()close() 了,簡(jiǎn)直不要太爽。

5. 如果你就是不想用 try-with-resources,也請(qǐng)手動(dòng)關(guān)閉資源

當(dāng)然,也不是所有項(xiàng)目都能用上 Java 7 及以上版本的語(yǔ)法,博主前些時(shí)間就接到了一個(gè)Java 6的項(xiàng)目咨詢,還真不是,你發(fā)任你發(fā),我用Java 8。哈哈,有些老項(xiàng)目沒(méi)法用 try-with-resources。那也不是不能寫(xiě),你只要自己負(fù)責(zé)把所有資源都在 finally 中手動(dòng)關(guān)閉,也一樣可以穩(wěn)穩(wěn)落盤(pán)。

注意關(guān)閉的順序要搞對(duì),先關(guān) workbook,再關(guān)輸出流。

示例如下:

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 會(huì)自動(dòng) flush
    } catch (IOException e) {
        e.printStackTrace();
    }
}

記?。篶lose() 會(huì)自動(dòng)調(diào)用 flush(),但你也可以顯式加一遍 flush(),確保保險(xiǎn)。

大 Excel 文件時(shí)內(nèi)存溢出風(fēng)險(xiǎn)

  • XSSFWorkbook 加載整個(gè) .xlsx 到內(nèi)存;
  • 寫(xiě)入也可能消耗大量?jī)?nèi)存;
  • 超過(guò)幾十萬(wàn)行時(shí)可能拋出 OOM。

大數(shù)據(jù)量推薦使用 SXSSFWorkbook:

SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook((XSSFWorkbook) workbook); 
sxssfWorkbook.write(outputStream);
sxssfWorkbook.dispose(); // 清理臨時(shí)文件

6. 工作簿數(shù)據(jù)本身也別忘了檢查

最后還有一個(gè)冷門(mén)但真實(shí)的情況是——你其實(shí)根本就沒(méi)有往 Workbook 里寫(xiě)任何東西。這樣寫(xiě)出來(lái)的 Excel 文件雖然也是合法的 .xlsx,但打開(kāi)后是空白頁(yè),或者打開(kāi)報(bào)錯(cuò),看上去像是“沒(méi)寫(xiě)進(jìn)去”,其實(shí)是你沒(méi)寫(xiě)進(jìn)去數(shù)據(jù)……

你可以加個(gè)調(diào)試代碼確認(rèn):

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

7. 防止“寫(xiě)了但沒(méi)落盤(pán)”的幾點(diǎn) checklist

檢查項(xiàng)建議
使用緩沖流BufferedOutputStream 性能更穩(wěn)
手動(dòng)或自動(dòng)關(guān)閉flush() + close 必不可少
優(yōu)先使用 try-with-resources推薦寫(xiě)法,防忘關(guān)
大文件用 SXSSFWorkbook防止內(nèi)存溢出
確認(rèn)實(shí)際寫(xiě)入數(shù)據(jù)不要生成空文件

以上就是Java使用FileOutputStream寫(xiě)Excel文件不落盤(pán)的解決方法的詳細(xì)內(nèi)容,更多關(guān)于Java FileOutputStream寫(xiě)Excel文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Mybatis之RowBounds分頁(yè)原理詳解

    Mybatis之RowBounds分頁(yè)原理詳解

    這篇文章主要介紹了Mybatis之RowBounds分頁(yè)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • SpringBoot+Mybatis使用Mapper接口注冊(cè)的幾種方式

    SpringBoot+Mybatis使用Mapper接口注冊(cè)的幾種方式

    本篇博文中主要介紹是Mapper接口與對(duì)應(yīng)的xml文件如何關(guān)聯(lián)的幾種姿勢(shì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • 淺談java中BigDecimal類的簡(jiǎn)單用法

    淺談java中BigDecimal類的簡(jiǎn)單用法

    這篇文章主要介紹了淺談java中BigDecimal類的簡(jiǎn)單用法,在開(kāi)發(fā)時(shí),如果我們需要精確計(jì)算的結(jié)果,必須使用BigDecimal類來(lái)操作。感興趣的話可以了解一下
    2020-07-07
  • Java類變量和成員變量初始化過(guò)程的應(yīng)用介紹

    Java類變量和成員變量初始化過(guò)程的應(yīng)用介紹

    昨天看了一本叫做《突破程序員基本功的16課》的書(shū),個(gè)人感覺(jué)還可以,主要對(duì)Java的技巧進(jìn)行了一些深入的講解,讓我對(duì)類的初始化和對(duì)象的創(chuàng)建有了新的認(rèn)識(shí)
    2013-04-04
  • java selenium處理Iframe中的元素示例

    java selenium處理Iframe中的元素示例

    本文主要介紹java selenium處理Iframe中的元素,這里整理了相關(guān)資料并附有示例代碼和實(shí)現(xiàn)方法,有需要的小伙伴可以參考下
    2016-08-08
  • mybatis-plus分頁(yè)查詢的實(shí)現(xiàn)實(shí)例

    mybatis-plus分頁(yè)查詢的實(shí)現(xiàn)實(shí)例

    頁(yè)查詢是一項(xiàng)常用的數(shù)據(jù)庫(kù)查詢方法,本文主要介紹了mybatis-plus分頁(yè)查詢的實(shí)現(xiàn)實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • java 計(jì)算中位數(shù)的實(shí)現(xiàn)方法

    java 計(jì)算中位數(shù)的實(shí)現(xiàn)方法

    這篇文章主要介紹了java 計(jì)算中位數(shù)的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • RabbitMQ下載與安裝教程

    RabbitMQ下載與安裝教程

    RabbitMQ是實(shí)現(xiàn)了高級(jí)消息隊(duì)列協(xié)議(AMQP)的開(kāi)源消息代理軟件(亦稱面向消息的中間件),這篇文章給大家介紹RabbitMQ下載與安裝教程,感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • Java8 stream 中利用 groupingBy 進(jìn)行多字段分組求和案例

    Java8 stream 中利用 groupingBy 進(jìn)行多字段分組求和案例

    這篇文章主要介紹了Java8 stream 中利用 groupingBy 進(jìn)行多字段分組求和案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • Spring AOP切點(diǎn)表達(dá)式使用及說(shuō)明

    Spring AOP切點(diǎn)表達(dá)式使用及說(shuō)明

    這篇文章主要介紹了Spring AOP切點(diǎn)表達(dá)式使用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05

最新評(píng)論

宜宾县| 郸城县| 乐业县| 米脂县| 山阴县| 灵丘县| 安化县| 平阳县| 探索| 崇信县| 林州市| 上虞市| 襄垣县| 淳化县| 崇义县| 元氏县| 荣昌县| 三河市| 五峰| 兴城市| 陇川县| 柘荣县| 桓仁| 吉木萨尔县| 祁东县| 德惠市| 康马县| 泸溪县| 大理市| 土默特右旗| 芦山县| 镇原县| 潜江市| 邳州市| 越西县| 广德县| 吴旗县| 乌海市| 如皋市| 凤阳县| 广汉市|