excel2007海量小内存回收问题数据读取,内存益处问题怎么处理

17:36 提问
poi处理excel大数据量的导入会报内存溢出
XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(fileName()));
就是单独执行这行代码都不行,报内存溢出,我把虚拟机都设置成最大了也溢出
差不多10万行吧
按赞数排序
----------------------biu~biu~biu~~~在下问答机器人小D,这是我依靠自己的聪明才智给出的答案,如果不正确,你来咬我啊!
可以参考这:poi的eventmodel写的大数据量的excel的读取程序。
或者换一种excel操作工具jxf。
LZ可以试试分批处理,如下,当list中接收到的数据到1W条后,就先去去保存到数据库中,
同时将list清空,等待接收接下来的内容,直到将数据接收完毕
while(判断excel文件中是否还有信息){
list.add(XXX);
if(num &= 10000){
执行导入操作,同时将list清空,将num置为0
if(null != list && list.size() & 0){
执行导入操作,同时将list清空(这是对剩余数据的操作)
其他相似问题最近在测试上传Excel2007大文件的功能,采用的是Apache POI工具。
Excel2007: 24M , POI :3.10
发现POI在处理24MExce2007l文件的时候,几乎占用了2G的Heap Space.
由于Excel2007的文件是经过压缩的,其实数据都是存放在shareStringl.xml文件中。
所以24M的文件,经过解压缩后,其实有160M的大小。
经过Debug发现,POI在处理shareString.xml文件的时候,Heap内存就一直在飙升.最后导致内存的溢出,只
能加大Heap Space.
问题:说明POI在处理Excel2007的时候占用了很大的内存,那么有没有更好的方法来读取Excel文件呢?
首先先去http://poi.apache.org/faq.html :这个是个常用的问题列表,在
14. I think POI is using too much memory! What can I do?
This one comes up quite a lot, but often the reason isn&t what you might initially think. So, the first thing to check is - what&s the source of the problem? Your file? Your code? Your environment? Or Apache POI?
Next, use the example program
to try reading the a file in with HSSF or XSSF. Related is
, which uses SAX parsing for .xlsx
我们看到了POI已经提出了针对这个问题的回答,而且正好在XLS2CSV中找到了很好的解决读取大容量的方法.
在XLS2CSV中,即使是读取300M的2007excel文件也没有什么问题,占用的内存也是可以接受的。
在这段代码中的注释中写出了下面一段话:
*Data sheets are read using a SAX parser to keep the
* memory footprint relatively small, so this should be
* able to read enormous workbooks.
The styles table and
* the shared-string table must be kept in memory.
* standard POI styles table class is used, but a custom
* (read-only) class is used for the shared string table
* because the standard POI SharedStringsTable grows
* very quickly with the number of unique strings.
大概的意思就是说通用的处理方法会快速消耗掉内存,所以采用了 SAX parser方法来处理大容量的文件.
public void processSheet(
StylesTable styles,
ReadOnlySharedStringsTable strings,
InputStream sheetInputStream)
throws IOException, ParserConfigurationException, SAXException {
InputSource sheetSource = new InputSource(sheetInputStream);
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxFactory.newSAXParser();
XMLReader sheetParser = saxParser.getXMLReader();
ContentHandler handler = new MyXSSFSheetHandler(styles, strings, this.minColumns, this.output);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
上面的一段代码是比较核心的代码,通过SAXParser解析xml文件,尽量不占用内存资源,从而达到读取大文件的目的。
代码下载: http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java
相关 [poi excel 文件] 推荐:
- 编程语言 - ITeye博客
最近在测试上传Excel2007大文件的功能,采用的是Apache POI工具.
发现POI在处理24MExce2007l文件的时候,几乎占用了2G的Heap Space..
由于Excel2007的文件是经过压缩的,其实数据都是存放在shareStringl.xml文件中.
- 博客园_首页
基本思路:点击导出后生成临时.xls文件,返回文件名,供用户下载,下载完后删除文件.
带查询的导出(前端EasyUI),如下为导出界面图.
下面为导出按钮绑定的函数:. var exportCondition={};//导出条件.
//按条件进行查询数据,首先我们得到数据的值.
- ITeye博客
前言:今天在项目中看到有小模块是上传Excel解释后保存到数据库的操作,好奇之下去了解了如何使用Apache POI操纵Excel和Word,以下为小分享.
POI是Apache下的一个项目,是用Java编写的开源框架,提供API供开发者直接操作Microsoft Office(Excel,Word,PowerPoint...).
- ITeye博客
前些日子把JXL替换为ApachePOI,原因很简单,JXL在2009年10月已经停止更新,并且不支持Excel 2007 OOXML (.xlsx)格式的文件. 事实上把JXL与POI进行比较并不公平,因为JXL只能够操作OLE2格式的Excel(即.xls),而POI则是能够读写xls(x)、doc(x)、ppt(x)的一整套解决方案.
- 开源软件 - ITeye博客
读docx文件. 1.1
通过XWPFWordExtractor读. 1.2
通过XWPFDocument读. 2
写docx文件. 2.1
直接通过XWPFDocument生成. 2.2
以docx文件作为模板.
- CSDN博客数据库推荐文章
利用kettle组件导入excel文件到数据库.
把excel文件内容导入到目标表中;然后用java调用kettle的转换. excel文件的内容只有两列,示例如下:.
数据库表的结构如下:. 使用oracle函数解决上图黄色行的字段:两个uuid和两个系统日期;. 需要生成uuid,这个在oracle中可以利用SYS_UUID()函数实现;.
- syeye - scofield PHP开发-SEO SEM
最近做一个项目,其中涉及到了数据导成excel的功能. 后来使用了 开源的 PHPExcel
/ 目前最新版是1.7.6. PHPExcel 可以生成 .xls 和 .xlsx (office2007). 比如设置 excel的title,keywords,description.
- ITeye博客
直接上代码:. POI_图文混排_S3_Test t = new POI_图文混排_S3_Test();. setTextFontInfo(p, false, false, &基本实验技能(常见实验仪器及基本操作)&, &宋体&, &000000&,.
- 开源软件 - ITeye博客
通过birt下载含有分组的报表后,会发现,在分组字段的后面会多出一行空白行,看上去很丑,在查阅很多资料后,才有现在的解决方法.
那就是把分组的那一行去掉,将分组的字段融合进详情那一行. 通过脚本判断,当前这一行的分组的数据是否等于上一行的数据. 比如我这有一张报表,按照订单号分组显示.
- ITeye博客
用Excel做数据分析——直方图. 已有
0 人发表留言,猛击-&&
这里&&-参与讨论. —软件人才免语言低担保 赴美带薪读研.
坚持分享优质有趣的原创文章,并保留作者信息和版权声明,任何问题请联系:@。查看: 5916|回复: 14|关注: 0
大量数据处理,内存不够咋办
<h1 style="color:# 麦片财富积分
新手, 积分 5, 距离下一级还需 45 积分
关注者: 1
我的数据是一个excel表格,
包含96个工作表,
每个工作表有三列数据,但都差不多要十几万行。
附件含我写的代码、、、、略乱、头痛,完全菜鸟级选手不知道怎么改进啊
备注里的某些display是之前处理一个只有5个工作表的数据文件
(9.22 KB, 下载次数: 88)
23:37 上传
点击文件名下载附件
对96个工作表的数据处理时出错在此,(另、数据文件达几十M无法上传)
Error using accumarray
Out of memory. Type HELP MEMORY for your options.
Error in fast (line 165)
& & s1{i} = accumarray(round(num{i}(:,1)*1000),num{i}(:,2));
数据就是这样,每个工作表都如此
m/zIntensityRelative50,005417210,0150,00841253,30,0150,039812220,0150,06853189,90,0350,06891270,50,0150,0696976,90,0150,071514,80,0150,07035444,30,0550,07035384,80,0550,07067628,60,0750,07089975,80,0950,071233697,20,2950,07151195711,0450,07170,8950,071883559,80,7250,072231729,40,2750,072314056,70,1250,072410154,40,09
此外曾经有个大哥出手相助,给出这样的代码,
太愚钝了,看不明白,而且运行时出错、
c = cellfun(@(x)x(:,1),num,'un',false)';
m = unique(cell2mat(c));
c = bsxfun(@(num,b)ismember(num,c{b}),m,1:length(c));
m = double(c);
t = cell2mat(num(:));
m(c) = t(:,2);
我觉得这个能替换掉我用的accumarray,但是不知道能不能解决内存的问题、但是第一句就看不懂
帖子最佳答案
关注者: 182
什么错误,然后你真的需要把所有数据都一次读入内存吗?
<h1 style="color:# 麦片财富积分
关注者: 1
honglei.chen 发表于
什么错误,然后你真的需要把所有数据都一次读入内存吗?
Error using accumarray
Out of memory. Type HELP MEMORY for your options.
Error in fast (line 165)
& & s1{i} = accumarray(round(num{i}(:,1)*1000),num{i}(:,2));
那个、、、不是一次读入的话还能怎么办?
帖子最佳答案
关注者: 182
wjwfish 发表于
Error using accumarray
Out of memory. Type HELP MEMORY for your options.
[num,txt,raw] = xlsread(filename,sheet,range) reads from the specified sheet and range.
<h1 style="color:#89 麦片财富积分
关注者: 107
s1和s2在循环后根本没有用到对不对?这样的话,就没有必要保留它们从1到L的所有值。
也就是说,不是写成
s1 = cell(1,L)
s1{i} = ...
<h1 style="color:# 麦片财富积分
关注者: 1
stellari 发表于
s1和s2在循环后根本没有用到对不对?这样的话,就没有必要保留它们从1到L的所有值。
也就是说,不是写成
for i=1:L&&
提到最外面,您觉得可行吗?
我把他提到最外面之后。运算结果和原来不一样,而且作图只有最后一个点。
这是我以一个10个工作表的文件的练习。96个工作表的根本无法运行
<h1 style="color:# 麦片财富积分
关注者: 1
honglei.chen 发表于
[num,txt,raw] = xlsread(filename,sheet,range) reads from the specified sheet and range.
所以我把for i=1 L这个循环放得更外面了、、、、但是我的运算结果,final他少了好多数据
<h1 style="color:# 麦片财富积分
试试importdata命令吧 太大的矩阵别用xlsread
关注者: 209
royalsniper 发表于
试试importdata命令吧 太大的矩阵别用xlsread
importdata在处理excel的文件类型时同样调用的是xlsread
<h1 style="color:# 麦片财富积分
kaaaf123 发表于
importdata在处理excel的文件类型时同样调用的是xlsread
机理不太清楚~&&
我遇到跟LZ同样问题的时候 xlsread出错,显示空间不足无法完成操作;而importdata很顺利的把数据读出来了
站长推荐 /2
Powered by百万级数据量导出EXCEL解决方案分析 | 集深数据系统_报表系统
1. 问题概述 在web页面上显示的报表导出到excel文件里是一种很常见的需求, 润乾报表的类excel模型,支持excel文件数据无失真的导入导出, 然而,当数据量较大的情况下,就会遇到一些问题: 1. 2003Excel本身的支持最多65535行数据 2. 在这种大数据量的报表生成和导出中,要占用大量的内存,甚至内存溢出 难点:1.数据量大,报表在运算成ireport对象时每个sheet页内存不释放,可能内存溢出. 2.即使能够运算完ireport对象再导出Excel的过程中内存不释放,可能内存溢出.
2 . 案例 上海期货交易所 上海唯智信息
3. 解决方案 一. 对于数据超过了65535行的问题,很自然的就会想到将整个数据分块,利用excel的多sheet页的功能,将超出65535行后的数据写入到下一个sheet页中,即通过多sheet页的 方式,突破了最高65535行数据的限定, 具体做法就是,单独做一个链接,使用JSP导出,在JSP上通过程序判断报表行数,超过65535行后分SHEET写入。这样这个问题就得以解决了 二. 在这种大数据量的报表生成和导出中,要占用大量的内存,尤其是在使用TOMCAT的情况下,JVM最高只能支持到2G内存,则会发生内存溢出的情况。此时的内存开销 主要是两部分,一部分是该报表生成时的开销,另一部分是该报表生成后写入一个EXCEL时的开销。由于JVM的GC机制是不能强制回收的,因此,对于此种情形,我们要改变一种方式: 1. 将该报表设置起始行和结束行参数,在API生成报表的过程中,分步计算报表,比如一张20万行数据的报表,在生成过程中,可通过起始行和结束行分4-5次进行。这样,就 降低了报表生成时的内存占用,在后面报表生成的过程中,如果发现内存不够,即可自动启动JVM的GC机制,回收前面报表的缓存 2. 导出EXCEL的过程,放在每段生成报表之后立即进行,改多个SHEET页为多个EXCEL,即在分步生成报表的同时分步生成EXCEL,则通过 POI包生成EXCEL的内存消耗也得以降低。通过 多次生成,同样可以在后面EXCEL生成所需要的内存不足时,有效回收前面生成EXCEL时占用的内存 3. 再使用文件操作,对每个客户端的导出请求在服务器端根据SESSIONID和登陆时间生成唯一的临时目录,用来放置所生成的多个EXCEL,然后调用系统控制台,打包多个EXCEL为RAR 或者JAR方式,最终反馈给用户一个RAR包或者JAR包,响应客户请求后,再次调用控制台删除该临时目录。 4. 通过分段运算和生成,有效降低了报表从生成结果到生成EXCEL的内存开销。其次是通过使用压缩包,响应给用户的生成文件体积大大缩小,降低了多用户并 发访问时服务器下载文件的负担,有效减少多个用户导出下载时服务器端的流量,从而达到进一步减轻服务器负载的效果
4. 程序部分 1.JSP里导出的链接格式:&a href=“&%=request.getContextPath()%&/exportToExcel.jsp?report=分页标签.raq&path=reportFiles\&param=arg1=123,234;arg2=2″&导出Excel&/a& 也可用javascript的方式 2.导出EXCEL中对于取最大行数,可以在报表里多定义一个数据集专门取最大行数,在后台通过API方式解析,保证通用性避免代码中出现SQL,复杂SQL,存储过程等,如图:
jsp具体代码: &%@ page contentType=”text/charset=GBK“%& &%@ page import=”com.runqian.report4.model.*”%& &%@ page import=”com.runqian.report4.usermodel.*“%& &%@ page import=”com.runqian.report4.view.excel.*”%& &%@ page import=”com.runqian.report4.util.*”%& &%@ page import=”java.util.ArrayList“%& &%@ page import=”java.io.*”%& &%@ page import=”java.sql.*“/& &html& &head& &title&导出EXCEL&/title& &/head& &body& &% request.setCharacterEncoding(“GBK“); String root = getServletContext().getRealPath(“/”); String path = request.getParameter(“path“); //相对路径 String report = request.getParameter(“report“); //报表名 String param = request.getParameter(“param“); //报表参数 String filePath = root + path + ReportDefine rd2 = (ReportDefine) ReportUtils.read(filePath);//读取报表 Context context = new Context(); // 获得报表定义中的数据集集合 DataSetMetaData dsmd = rd2.getDataSetMetaData(); // 取到需要修改的数据集对象 //SQL检索类型:SQLDataSetConfig //复杂SQL类型:CSQLDataSetConfig //存储过程类型:ProcDataSetConfig SQLDataSetConfig dsc = (SQLDataSetConfig) dsmd.getDataSetConfig(0); String sql = dsc.getSQL(); //连接数据库,查询查询有多少条记录 Connection conn = context.getConnectionFactory(“zHouHuiHui“) .getConnection(); ResultSet rs = Statement stmt = conn.createStatement(); rs = stmt.executeQuery(sql); int num = 0; try { if (rs.next()) { num = rs.getInt(1); System.out.println(“条数:” + num); } } catch (SQLException e) { e.printStackTrace(); } finally { if (rs != null) rs.close(); if (stmt != null) stmt.close(); } int rowCount = 65536;//每页最大行数 int pageCount = 0; if (num % rowCount == 0) { pageCount = num / rowC } else { pageCount = num / rowCount + 1; } System.out.println(“总共多少页 :” + pageCount); try { for (int k = 0; k & pageC k++) { //读取报表模板 context = new Context(); ReportDefine rd = (ReportDefine) ReportUtils.read(filePath); //运算报表 //创建要导出的excel报表 ExcelReport excel = new ExcelReport(); //计算前,设置参数 ParamMetaData pmd = rd.getParamMetaData(); if (param != null && param.trim().length() != 0 && pmd != null) { String[] para = param.split(“;”); String[] pa = String paramName = “”; //参数名 String paramValue = “null”; //参数值 for (int i = 0; i & para. i++) { out.println(para[i]); pa = para[i].split(“=”); paramName = pa[0]; if (pa.length == 1) { paramValue = “”; context.setParamValue(paramName, paramValue); } else { if (pa[1].indexOf(“,”) == -1) { paramValue = pa[1]; context .setParamValue(paramName, paramValue); } else { ArrayList objArrayList = new ArrayList(); String[] b = pa[1].split(“,”); for (int j = 0; j & b. j++) { objArrayList.add(b[j]); } context.setParamValue(paramName, objArrayList); } } } } context.setParamValue(“startRow“, 30000 * k); context.setParamValue(“endRow“, 30000 * (k + 1)); System.out.println(context.getParamValue(“startRow”)); System.out.println(context.getParamValue(“endRow”)); Engine enging = new Engine(rd, context); IReport iReport = enging.calc(); System.out.println(“[ToExcelServlet] – 运算报表结束!”); PrintSetup ps = iReport.getPrintSetup(); //取打印 ps.setPagerStyle(PrintSetup.PAGER_ROW); //设置报表分页方式为按数据行数分页 ps.setPaper((short) 0); //设置纸张类型 ps.setPaperWidth(1000); ps.setRowNumPerPage(65535); //设置按数据行数分页时每页的数据行数 iReport.setPrintSetup(ps); //设置打印配置*/ PageBuilder pb = new PageBuilder(iReport); //根据iReport中的PrintSetup里的信息进行分页 IReport[] ireports = pb.getAllPages(); //获得分页后的所有页集合 for (int i = 0; i & ireports. i++) { excel.export(ireports[i]); } excel.saveTo(“d://test//test” + k + “.xls”); } //将1个文件压缩成RAR格式 ExcelOutPut objRARFile = new ExcelOutPut(); int arg = objRARFile.RARFile(“d://test”, “d://test”, “”); OutputStream objOutputStream = response.getOutputStream(); response.setContentType(“application/octet-stream“); String httpHeader = “filename=report1.rar“; response.addHeader(“Content-Disposition”, httpHeader); FileInputStream infile = null;// 读取文件用 //生成对象用infile,准备读取文件 infile = new FileInputStream(“D://test.rar“); byte[] buffer = new byte[500]; int count = 0; count = infile.read(buffer); while (count & 0) { objOutputStream.write(buffer, 0, count); count = infile.read(buffer); } //ServletOutputStream sos = response.getOutputStream(); objOutputStream.close(); infile.close(); //以下两句必须要加,否则会报响应的输出流已经被占用 out.clear(); out = pageContext.pushBody(); } catch (Exception e) { e.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } %& &/body& &/html& 3.将文件压缩成RAR格式,ExcelOutPut.java,具体代码: package com.runqian.report4. import java.io.BufferedR import java.io.IOE import java.io.InputStreamR public class ExcelOutPut { /* * * cmd 下调试成功的命令 * * 压缩:Rar a c:\test.rar c:\3Out_.MDB * * 解压:UnRar x * c:\test.rar d:\ * */ private static String rarCmd = “C://Program Files//WinRAR//Rar.exe a “; private static String unrarCmd = “C://Program Files//WinRAR//UnRar x “;
private static int count = 0; /** * * 将1个文件压缩成RAR格式 * * rarName 压缩后的压缩文件名(不包含后缀) * * fileName 需要压缩的文件名(必须包含路径) * * destDir 压缩后的压缩文件存放路径 * return 0 表示压缩完成 * * 1 表示由于一些原因失败 * * * @throws IOException * * @throws InterruptedException * */
public static int RARFile(String rarName, String fileName, String destDir) { rarCmd += destDir + rarName + “.rar ” + fileN String readStr = “”; try { System.out.println(“正在压缩文件…” + rarName + “.rar “); S Process p = Runtime.getRuntime().exec(rarCmd); BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(p.getInputStream())); while ((s = bufferedReader.readLine()) != null) System.out.println(s); try { p.waitFor(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(rarCmd); System.out.println(“finished rar the file: ” + fileName); } catch (IOException e) { e.printStackTrace(); return 1; } return 0; } public static void main(String[] args) { // TODO Auto-generated method stub // ExcelOutPut objRARFile = new ExcelOutPut(); // objRARFile.RARFile(“d://test”, “d://test”, “”); int count = 199999; // 记录数 count = count / 30000 + 1; System.out.println(count); } } 5. 总结 1. 该问题本身并不是润乾报表运算或者生成时有内存溢出BUG,而是WEB容器本身的问题和JVM本身的机制问题 2. 经过外部API改造,可以使用方法对问题进行规避 3. 该案例具有一定的通用性,完全可以做成一个独立的大报表导出的功能,将大数据量的报表分段运算成多个EXCEL,PDF或者WORD,通过外部程序进行压缩处理,响应给用户压缩包 4. 该需求本身合理性值得斟酌,但存在就是合理,也需要客户的配合,让步最终导致了该问题的解决

我要回帖

更多关于 npoi读取excel2007 的文章

 

随机推荐