在使用POI进行excel操作时,当数据量较大时经常会产生内存溢出异常。下面我们通过分析如何解决该问题
一、POI结构图
二、内存溢出问题
在项目中遇到二十万行数据要写入到excel中时会内存溢出,一般方法是调大tomcat的内存,但是调到2048M还是会内存溢出报错。因此我们分析其原因。我们通过分析其源码,得出其实现步骤为通过InputStream一行行读取到TreeMap类型的HSSFRow结构体中,因此当数据量大时就会造成内存溢出。
public HSSFWorkbook(DirectoryNode directory, boolean preserveNodes) throws IOException { super(directory); String workbookName = getWorkbookDirEntryName(directory); this.preserveNodes = preserveNodes; // If we're not preserving nodes, don't track the // POIFS any more if(! preserveNodes) { clearDirectory(); } _sheets = new ArrayList<HSSFSheet>(INITIAL_CAPACITY); names = new ArrayList<HSSFName>(INITIAL_CAPACITY); // Grab the data from the workbook stream, however // it happens to be spelled. InputStream stream = directory.createDocumentInputStream(workbookName); List<Record> records = RecordFactory.createRecords(stream); workbook = InternalWorkbook.createWorkbook(records); setPropertiesFromWorkbook(workbook); int recOffset = workbook.getNumRecords(); // convert all LabelRecord records to LabelSSTRecord convertLabelRecords(records, recOffset); RecordStream rs = new RecordStream(records, recOffset); while (rs.hasNext()) { try { InternalSheet sheet = InternalSheet.createSheet(rs); _sheets.add(new HSSFSheet(this, sheet)); } catch (UnsupportedBOFType eb) { // Hopefully there's a supported one after this! log.log(POILogger.WARN, "Unsupported BOF found of type " + eb.getType()); } } for (int i = 0 ; i < workbook.getNumNames() ; ++i){ NameRecord nameRecord = workbook.getNameRecord(i); HSSFName name = new HSSFName(this, nameRecord, workbook.getNameCommentRecord(nameRecord)); names.add(name); } }
/** * add a row to the sheet * * @param addLow whether to add the row to the low level model - false if its already there */ private void addRow(HSSFRow row, boolean addLow) { _rows.put(Integer.valueOf(row.getRowNum()), row); if (addLow) { _sheet.addRow(row.getRowRecord()); } boolean firstRow = _rows.size() == 1; if (row.getRowNum() > getLastRowNum() || firstRow) { _lastrow = row.getRowNum(); } if (row.getRowNum() < getFirstRowNum() || firstRow) { _firstrow = row.getRowNum(); } }
excel数据行读取到内存的存储结构如下:
三、解决方案
poi官网给了一种大批量数据写入的方法,使用SXXFWorkbook类进行大批量写入操作解决了这个问题,可以监控该样例,我们会发现整体内存呈现锯齿状,能够及时回收,内存相对比较平稳。
package org.bird.poi; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; 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.util.CellReference; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.junit.Assert; public class XSSFWriter { private static SXSSFWorkbook wb; public static void main(String[] args) throws IOException { wb = new SXSSFWorkbook(10000); Sheet sh = wb.createSheet(); for(int rownum = 0; rownum < 100000; rownum++){ Row row = sh.createRow(rownum); for(int cellnum = 0; cellnum < 10; cellnum++){ Cell cell = row.createCell(cellnum); String address = new CellReference(cell).formatAsString(); cell.setCellValue(address); } } // Rows with rownum < 900 are flushed and not accessible for(int rownum = 0; rownum < 90000; rownum++){ Assert.assertNull(sh.getRow(rownum)); } // ther last 100 rows are still in memory for(int rownum = 90000; rownum < 100000; rownum++){ Assert.assertNotNull(sh.getRow(rownum)); } URL url = XSSFWriter.class.getClassLoader().getResource(""); FileOutputStream out = new FileOutputStream(url.getPath() + File.separator + "wirter.xlsx"); wb.write(out); out.close(); // dispose of temporary files backing this workbook on disk wb.dispose(); } }
相关推荐
poi读取大量数据会造成gc内存溢出的报错,由于垃圾回收机制无法将大量的对象及时的回收,而这些对象又会保存在内存中,会导致内存不够用的情况,这时候我们就需要使用新的方法,读取为cvs即可.此解决方案可支持千万数据的...
绝对原创,这是我在项目中解决大数据Excel导入时内存溢出问题而编写的Excel行级解析器。同时支持Excel-2003和Excel-2007,excel-2003解析采用poi的eventusermodel模式实现,2007采用xmlreader实现,经项目验证,...
解决poi读取excel2007出现内存溢出问题代码参
本资源是从之前的资源综合整理出来的代码,之前的代码不全,需要下载两次,为了...本资源解决的难题是导入大文件excel的时候,会报内存溢出的错误。 欢迎各位下载,解决用户的难题是我的宗旨,好的话给个评价,谢谢!
一个POI导出Excel万级数据分页实现 解决内存溢出问题 完整的 project demo 有数据库dmp文件
java 使用 poi 解析导入大数据量(几万数据量+)时,报出OOM。这是使用POI 第二种处理方法,解决大数据量导入内存溢出问题,并提升效率
针对读取、生成excel内存溢出问题,包括工具类和具体的实现
主要给大家介绍了关于Poi读取Excel引发内存溢出问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
完美解决java读取excel内存溢出问题,希望可以帮到大家
从http://download.csdn.net/detail/whatismvc/3696185 和http://download.csdn.net/detail/whatismvc/3694229 下载的, 处理大数据量的Excel 2007文件不内存溢出,我试过的最大数据是 26000行,222列的xlsx。
poi读取大数据量excel文件,避免内存溢出,行级操作 根据本网站的资源修改的。 将一些类路径错误全部进行了修正。 另外,需要自己在类路径里,放spring-context.jar和spring-beans.jar包。
根据这个设计方案,做了详细的实现,经项目验证,Excel文件20W条数据不成问题,因为Excel解析是我自己原创的行级处理器,不会一次性生成很多对象,因此不存在内存溢出现象,只要excel文件放得下,有多少记录都没问题...
POI数据应用解决方案
通用的POI导入导出Excel通用解决方案,
事件驱动解析是把文件转换成xml,然后一边读取一边解析,这样就对内存的占用就会很少,可以很好的处理poi出现OOM的问题。 maven添加需要的jar包 <groupId>org.apache.poi <artifactId>poi <version>3.15 ...
基于位置的服务数据,移动互联网位置信息服务,全国POI数据库百度Poi高德poi数据库
但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。...
<groupId>org.apache.poi <artifactId>poi-ooxml <version>3.10-FINAL 利用3.10-FINAL版本的poi,导出逻辑主要在FileDownloadUtils的createExcelFile方法
里面有poi3.2资源包,和很多总结出来的实例代码和解决方案,值得poi使用者拥有