Java通過(guò)導(dǎo)出超大Excel文件解決內(nèi)存溢出問(wèn)題
前言
將業(yè)務(wù)數(shù)據(jù)導(dǎo)出到Excel表中,導(dǎo)出任務(wù)數(shù)據(jù)量較大時(shí),導(dǎo)出的項(xiàng)目就會(huì)內(nèi)存溢出,本文通過(guò)Java操作Poi的SXSSFWorkbook類進(jìn)行導(dǎo)出,解決內(nèi)存溢出問(wèn)題。
1.采用Poi中的SXSSFWorkbook
在實(shí)現(xiàn)excel導(dǎo)出時(shí),在數(shù)據(jù)量過(guò)大的情況下,總是容易發(fā)生內(nèi)存溢出的情況??梢允褂肞OI提供的 SXSSFWorkbook 類來(lái)避免內(nèi)存溢出。

2.maven中引入Poi
<!-- poi start --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.2</version> </dependency> <!-- poi end -->
3.測(cè)試過(guò)程
先使用普通的寫法測(cè)試(XSSFWorkbook),編寫writeNormalExcelTest測(cè)試方法,寫入的行數(shù)太多時(shí),會(huì)報(bào)內(nèi)存溢出(在設(shè)置-server -Xmx64m -Xms64m -Xmn32m的情況下)。
接著編寫SXSSFWorkbook操作excel的測(cè)試,測(cè)試方法writeHugeExcelTest(同樣在設(shè)置-server -Xmx64m -Xms64m -Xmn32m的情況下),結(jié)果證明無(wú)內(nèi)存溢出,能完好的導(dǎo)出1000000行測(cè)試數(shù)據(jù),整個(gè)Java類代碼如下:
4.單元測(cè)試Java代碼
package cn.gzsendi.exceltest;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;
public class HugeExcelExportTest {
private int totalRowNumber = 1000000; //寫入的excel數(shù)據(jù)行數(shù)
private int totalCellNumber = 40; //excel每行共40列
//普通的寫入excel的方法,會(huì)消耗內(nèi)存,寫入的行數(shù)太大時(shí),會(huì)報(bào)內(nèi)存溢出
@Test
public void writeNormalExcelTest(){
Workbook wb = null;
FileOutputStream out = null;
try {
long startTime = System.currentTimeMillis();
wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet("Sheet 1");
//定義Row和Cell變量, Rows從0開(kāi)始.
Row row;
Cell cell;
for (int rowNumber = 0; rowNumber < totalRowNumber; rowNumber++) {
row = sheet.createRow(rowNumber);
for (int cellNumber = 0; cellNumber < totalCellNumber; cellNumber++) {
cell = row.createCell(cellNumber);
cell.setCellValue(Math.random()); //寫入一個(gè)隨機(jī)數(shù)
}
//打印測(cè)試,
if(rowNumber % 10000 ==0) {
System.out.println(rowNumber);
}
}
//Write excel to a file
out = new FileOutputStream("d:\\temp\\normalExcel_" + totalRowNumber + ".xlsx");
wb.write(out);
long endTime = System.currentTimeMillis();
System.out.println("process " + totalRowNumber + " spent time:" + (endTime - startTime) + " ms.");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(out != null) out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(wb != null) wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//結(jié)合臨時(shí)文件壓縮等寫入excel,默認(rèn)超過(guò)100行就寫到臨時(shí)文件,不會(huì)報(bào)內(nèi)存溢出
@Test
public void writeHugeExcelTest(){
SXSSFWorkbook wb = null;
FileOutputStream out = null;
try {
long startTime = System.currentTimeMillis();
wb = new SXSSFWorkbook();//默認(rèn)100行,超100行將寫入臨時(shí)文件
wb.setCompressTempFiles(false); //是否壓縮臨時(shí)文件,否則寫入速度更快,但更占磁盤,但程序最后是會(huì)將臨時(shí)文件刪掉的
Sheet sheet = wb.createSheet("Sheet 1");
//定義Row和Cell變量, Rows從0開(kāi)始.
Row row;
Cell cell;
for (int rowNumber = 0; rowNumber < totalRowNumber; rowNumber++) {
row = sheet.createRow(rowNumber);
for (int cellNumber = 0; cellNumber < totalCellNumber; cellNumber++) {
cell = row.createCell(cellNumber);
cell.setCellValue(Math.random()); //寫入一個(gè)隨機(jī)數(shù)
}
//打印測(cè)試,
if(rowNumber % 10000 ==0) {
System.out.println(rowNumber);
}
}
//Write excel to a file
out = new FileOutputStream("d:\\temp\\hugeExcel_" + totalRowNumber + ".xlsx");
wb.write(out);
long endTime = System.currentTimeMillis();
System.out.println("process " + totalRowNumber + " spent time:" + (endTime - startTime) + " ms.");
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (wb != null) {
wb.dispose();// 刪除臨時(shí)文件,很重要,否則磁盤可能會(huì)被寫滿
}
try {
if(out != null) out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(wb != null) wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.結(jié)論
導(dǎo)出excel數(shù)據(jù)量大時(shí),采用SXSSFWorkbook進(jìn)行操作,數(shù)據(jù)達(dá)到一定數(shù)據(jù)將寫數(shù)據(jù)到臨時(shí)文件,不會(huì)一直占用內(nèi)存,因此不會(huì)報(bào)內(nèi)存溢出
到此這篇關(guān)于Java通過(guò)導(dǎo)出超大Excel文件解決內(nèi)存溢出問(wèn)題的文章就介紹到這了,更多相關(guān)Java導(dǎo)出超大Excel文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Cloud Zuul路由規(guī)則動(dòng)態(tài)更新解析
這篇文章主要介紹了Spring Cloud Zuul路由規(guī)則動(dòng)態(tài)更新解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
Druid監(jiān)控分布式實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了Druid監(jiān)控分布式實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
java統(tǒng)計(jì)文件中每個(gè)字符出現(xiàn)的個(gè)數(shù)
這篇文章主要為大家詳細(xì)介紹了java統(tǒng)計(jì)文件中每個(gè)字符出現(xiàn)的個(gè)數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03
Java HashMap三種循環(huán)遍歷方式及其性能對(duì)比實(shí)例分析
這篇文章主要介紹了Java HashMap三種循環(huán)遍歷方式及其性能對(duì)比,結(jié)合具體實(shí)例形式分析了Java HashMap三種循環(huán)遍歷方式的實(shí)現(xiàn)方法、運(yùn)行效率及性能優(yōu)劣,需要的朋友可以參考下2019-10-10
Java編程Webservice指定超時(shí)時(shí)間代碼詳解
這篇文章主要介紹了Java編程Webservice指定超時(shí)時(shí)間代碼詳解,簡(jiǎn)單介紹了webservice,然后分享了通過(guò)使用JDK對(duì)Webservice的支持進(jìn)行Webservice調(diào)用實(shí)現(xiàn)指定超時(shí)時(shí)間完整示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-11-11
java Swing實(shí)現(xiàn)選項(xiàng)卡功能(JTabbedPane)實(shí)例代碼
這篇文章主要介紹了java Swing實(shí)現(xiàn)選項(xiàng)卡功能(JTabbedPane)實(shí)例代碼的相關(guān)資料,學(xué)習(xí)java 基礎(chǔ)的朋友可以參考下這個(gè)簡(jiǎn)單示例,需要的朋友可以參考下2016-11-11
springboot整合mybatis-plus逆向工程的實(shí)現(xiàn)
這篇文章主要介紹了springboot整合mybatis-plus逆向工程的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
SpringBoot下如何實(shí)現(xiàn)支付寶接口的使用
這篇文章主要介紹了SpringBoot下如何實(shí)現(xiàn)支付寶接口的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11

