<article class="baidu_pl">
<div id="article_content" class="article_content clearfix csdn-tracking-statistics" data-pid="blog" data-mod=popu_307 data-dsm = "post" >
<div id="content_views" class="markdown_views prism-atom-one-dark">
<p>近期發現做的excel導出功能會導緻記憶體溢出(推測),于是采用了SXSSFWork控制記憶體中存放的條數,搞了一個禮拜,碰到了許多問題,通過問題也對POI中的SXSSFWork有了深入的了解。在此做個總結。先上兩個官方文檔 <br>
官網POI中的介紹與執行個體
SXSSFWorkbook的API文檔
public class A{
public String read(){
XSSFWorkbook xssfWorkbook = null;
try {
try {
xssfWorkbook = new XSSFWorkbook(file.getInputStream());
} catch (Exception e) {
logger.error(e.getMessage(), e);
ResponseBean<List> responseBean = new ResponseBean<>();
responseBean.setCode(ResponseBean.FAIL_98);
responseBean.setMsg(“檔案上傳失敗”);
return responseBean;
}
int sheet_numbers = wb.getNumberOfSheets();//擷取表的總數
//擷取具體哪張表
XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
//擷取這張表的行數 (從0開始)
int lastRowNum = sheet.getLastRowNum();
List addBeans = new ArrayList<>();
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
for (int i = 1; i <= lastRowNum; i++) {
XSSFRow row = sheet.getRow(i);
if(row == null){
continue;
}
String enterpriseName = getStringCellValue(row.getCell(0));
if(!StringUtils.hasText(enterpriseName)){
continue;
}
String taxNo = getStringCellValue(row.getCell(1));
String linkMan = getStringCellValue(row.getCell(2));
String phoneNo = getStringCellValue(row.getCell(3));
String authCode = getStringCellValue(row.getCell(4));
RegistBindBean addBean=new RegistBindBean();
addBean.setEnterpriseName(enterpriseName);
addBean.setTaxNo(taxNo);
addBean.setLinkMan(linkMan);
addBean.setPhoneNo(phoneNo);
addBean.setUserType(user.getType());
addBean.setUserBussinessNo(user.getBussinessNo());
if(StringUtils.hasText(authCode)){
addBean.setAuthCode(authCode);
addBean.setRegistType(RegistTypeConstant.REGISTBIND);
}else {
addBean.setRegistType(RegistTypeConstant.SLIENT);
}
addBean.setCustomerFrom(CustomerFromConstant.LOCAL);
addBeans.add(addBean);
}
return registBindInterface.incomeBatch(addBeans);
} finally {
IOUtils.closeQuietly(xssfWorkbook);
}
}
private String getStringCellValue(XSSFCell cell) {
String cellValue = “”;
if(cell == null){
return “”;
}
switch (cell.getCellTypeEnum()) {
case STRING:
cellValue = cell.getStringCellValue();
break;
case NUMERIC:
cellValue = new DecimalFormat("#").format(cell.getNumericCellValue());
break;
case BOOLEAN:
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
default:
cellValue = “”;
break;
}
return cellValue;
}
//寫
{
FileOutputStream output = new FileOutputStream(new File(xls_write_Address)); //讀取的檔案路徑
SXSSFWorkbook wb = new SXSSFWorkbook(10000);//記憶體中保留 10000 條資料,以免記憶體溢出,其餘寫入 硬碟
for(int sn=0;sn<ls.size();sn++){
Sheet sheet = wb.createSheet(String.valueOf(sn));
wb.setSheetName(sn, sheetnames[sn]);
ArrayList<String[]> ls2 = ls.get(sn);
for(int i=0;i<ls2.size();i++){
Row row = sheet.createRow(i);
String[] s = ls2.get(i);
for(int cols=0;cols<s.length;cols++){
Cell cell = row.createCell(cols);
cell.setCellType(XSSFCell.CELL_TYPE_STRING);//文本格式
sheet.setColumnWidth(cols, s[cols].length()*384); //設定單元格寬度
cell.setCellValue(s[cols]);//寫入内容
}
}
}
wb.write(output);
output.close();
}
}
使用時注意一下幾點:
1、SXSSF是限制滑動視窗中的行的通路來實作低記憶體的占用,注意是限制的是通路;
2、滑動視窗的預設大小windowSize為100,是由SXSSFWorkbook.DEFAULT_WINDOW_SIZE定義。
3、可new一個新的SXSSFWorkbook(int windowSize)在工作簿建構時指定視窗大小 ,例如:
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
此時wb的滑動視窗大小為1000;
4、windowSize為-1時,表示可以無限制通路。此種情況下,所有未調用flushRows()重新整理的記錄都可用于随機通路;
5、SXSSF中的資料達到滑動視窗的限制數量,會産生臨時檔案且不會自動删除(Win和Linux的預設路徑不同),通過調用dispose方法即可删除臨時檔案:
SXSSFWorkbook wb = new SXSSFWorkbook(100);
//假裝有許多操作
wb.dispose();
6、使用createRow()建立新行且未重新整理記錄的總數超過指定的視窗大小時,具有最低索引值的行将被重新整理,并且不能再通過getRow()通路。
比如視窗行數為100,記憶體目前有100行,createRow()建立一個新行,索引值為0的那一行被重新整理到本地檔案,該行将無法通路,因為它們已寫入磁盤了。(這一點解釋了我上一篇由空白行引起的問題,傳送門)
目前僅有這一些,後期碰到新的知識點會繼續補充。