POI操作Excel2007实例二之“SXSSFWorkbook”处理海量数据

解决java poi海量数据导出内存溢出问题 找了很多天的解决方法,一直被分页查询绕进去了,其实数据都能查出来的,真正卡的地方是ExcelExportUtil类下调错了方法。最开始调用的是这个方法,最主要的地方就是我标记的地方  workbook = new HSSFWorkbook();和workbook = new XSSFWorkbook();我先说说这两个方法作用:1.HSSFWorkbook:是操作Excel2003以前(包括200... 阅读详情

前文链接POI实现读写Excel2007完整示例--每分钟约处理7000行数据 


前文讲述了 POI 读取的基本操作,但后期 经过试验,当写入数据量超过5万条以上时,

很容易报错“内存溢出”,就算你调整JVM的xmx为 “2048MB”,也无效果。

后来查资料得知 SXSSFWorkbook 是专门用来处理大量数据写入 Excel2007的问题的。


实例如下,具体步骤神马的,请看前文。

读取仍然是“XSSFWorkbook”,写入则为“SXSSFWorkbook ”。

经试验 写入处理速度在 7000行左右,根据 Excel文件大小 会上下浮动。



Config.java

package com.excel.poi.gz10000;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.text.NumberFormat; 
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
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.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;       
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * <b> 数据匹配</b> <br>
 * <ul>
 * <li> 作者:C_Dream </li>
 * <li> 当前版本:4.0 </li>
 * <li> 修改时间: 2012-12-6 17:50 </li>
 * <li> 修改内容:<ol>
 * <li> 更换Excel2007写入方式,大幅提升性能。</li>
 * <li> 引入 log4j,局部提升性能。</li>
 * <li> 部分代码优化,CMD输出提示可选。</li>
 * </ol></li>
 * <li> 创建时间: 2012-11-08 19:22 </li>
 * </ul>
 */
public class Config extends HttpServlet{
	private static final long serialVersionUID = 1L;	 
	//Config c = new Config();//此处决不能 new 本类,否则报错:java.lang.StackOverflowError
	String class_path = this.getClass().getResource("").getPath(); 
	public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
	{
		this.doGet(request,response); //将 表单  post 方法传过来的参数,转给 get方法 去处理
	}
	public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException 
	{
	     request.setCharacterEncoding("UTF-8");	//转码
	     String forms=(String)request.getParameter("forms");

	     if(forms.equals("if_3g")){
				try {
					this.read_Excel(request,response);
				} catch (SQLException e) {
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}  
	     }
	     	     
		 response.sendRedirect("index.jsp?done=true");
	} 
	
	
	@SuppressWarnings("rawtypes")
	public void read_Excel(HttpServletRequest request,
			HttpServletResponse response) throws UnsupportedEncodingException, SQLException, ClassNotFoundException  {
		
		PropertyConfigurator.configure(class_path+"log4j.properties");//获取 log4j 配置文件
		Logger logger = Logger.getLogger(Config.class ); //获取log4j的实例
		String startTmie = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
		logger.debug("\n**********【准备处理,正在加载文件】**********");//7
		logger.debug("\n\n**********每行数据间请不要有空行,以免程序误判**********");//7
		logger.debug("\n\n**********由于处理Excel的插件本身性能局限,请控制文件大小,以免影响加载效率。**********");//7
		logger.debug("\n\n**********大小在\t 7 MB \t以内,大约\t 21 万 \t行数据。**********");//7
		logger.debug("\n\n**********本程序每分钟约处理 7000条数据,但根据文件大小会有影响。**********");//7
		
		request.setCharacterEncoding("UTF-8");	//转码
	    String xls_read_Address=(String)request.getParameter("xls_read_Address");//读取	
	    String xls_write_Address=(String)request.getParameter("xls_write_Address");//写入
	    String  count_rows=(String)request.getParameter("count_rows");//自动编号    
	    String  tips_cmd=(String)request.getParameter("tips_cmd");//CMD窗口的提示方式
	    
	    try { 
	    	DataConvert dc = new DataConvert();//数据转换工具
	    	DecimalFormat df = (DecimalFormat) NumberFormat.getPercentInstance(); 
	    	
	    	ArrayList<ArrayList> ls = new  ArrayList<ArrayList>();
 	
	    	File excel_file = new File(xls_read_Address);//读取的文件路径  
	    	FileInputStream input = new FileInputStream(excel_file);  //读取的文件路径 
            XSSFWorkbook wb = new XSSFWorkbook(new BufferedInputStream(input));                  
            int sheet_numbers = wb.getNumberOfSheets();//获取表的总数
            logger.debug("\n\n**********共有工作表总数**********:"+sheet_numbers);//7  
            String[] sheetnames=new String[sheet_numbers];
            
    		Connection con=null;
    	    Statement  stmt=null;
    	    ResultSet  rs=null;
    	    String s_3g=null;   	    
    		Class.forName("oracle.jdbc.driver.OracleDriver");
    		con = DriverManager.getConnection("jdbc:oracle:thin:@12.12.12.123:1521:gz10000","gz12345","12345");
    		stmt = con.createStatement();	
    	    
            for(int i=0;i<sheet_numbers;i++){//遍历所有表           	
    	    	ArrayList<String[]> ls_a = new  ArrayList<String[]>(); //用来存储某个表 读取出来的数据  
                Sheet sheet = wb.getSheetAt(i);  //获取 某个表              
                sheetnames[i] = sheet.getSheetName();//获取表名,存入数组
                logger.debug("\n\n---正在读取和匹配工作表\t《"+sheetnames[i]+"》\t的数据---\n");//7 
                
                int rows_num = sheet.getLastRowNum();//获取行数
                logger.debug("\n\n---表\t《"+sheetnames[i]+"》\t 共有数据---:\t"+rows_num+"\t行");//7 
                for( int rows=0;rows<rows_num;rows++){ 
                	Row row = sheet.getRow(rows);//取得某一行   对象                	               	
                	
                	if(row!=null&&!(row.equals(""))){
                	int columns_num = row.getLastCellNum();//获取列数
                	
                	String[] s =new String[5];//初始化数组长度
            		for( int columns=0;columns<columns_num;columns++){
            			Cell  cell = row.getCell(columns);            		
            			if(cell!=null){ 
            			switch ( cell.getCellType()) {  
                         case XSSFCell.CELL_TYPE_STRING: // 字符串   
                        	 s[columns] = cell.getStringCellValue();  
                        	 if(s[columns]==null){
                        		 s[columns]=" ";
                        	 }
                             break; 
                         case XSSFCell.CELL_TYPE_NUMERIC: // 数字                        	 
                        	    double strCell = cell.getNumericCellValue();
                           	 if(String.valueOf(strCell)==null){
                        		 s[columns]=" ";
                        	 }  
                                    
                                df.applyPattern("0");
                                s[columns] = df.format(strCell);
                                if(Double.parseDouble(s[columns])!=strCell){
                                 df.applyPattern(Double.toString(strCell));
                                 s[columns] = df.format(strCell);
                                }
                        	 
                             break;
                         case XSSFCell.CELL_TYPE_BLANK: // 空值   
                        	 s[columns]=" ";  
                             break;   
                         default:  
                        	 logger.debug("\n---单元格格式不支持---");    
                             break;   
                         }  
            		   }
                	}
            		if(count_rows.equals("是")&&rows>0){
            			s[0]=dc.intToString(rows);//自动编号
            		}
            		
            		/* ******** 访问数据库 ,并判断是否3G ******** */
            		String sql="select busiattr1 from ap_t_si_cus_spec_info where cus_phone='"+s[1]+"' and rownum=1";					    
        		    rs = stmt.executeQuery(sql);
        		    
        		    if(rs.next()){
        		    	if(rs.getString("busiattr1")!=null){
        		    		s_3g = rs.getString("busiattr1").toString().toUpperCase();
        		    	}
        		    	else{
        		    		s_3g=" ";
        		    	}
        			}
        		    else{
        	    		s_3g=" ";
        	    	} 
        		    /* ******** 访问结束  ******** */
        		    
        			if(s_3g.contains("3G")){
        				s[4]="是";//写入 “是否3G”这一列 的值,比如 “是”
        			}
        			if(s[4]==null){
        				s[4]="\t";
        			}
        			
        			/* CMD窗口提示方式 */
        			if(!(tips_cmd.equals("none"))&&tips_cmd!=null&&!(tips_cmd.equals(""))) {
	                	if(tips_cmd.equals("all")){
	                		logger.debug("\n匹配中:"+s[0]+"\t"+s[1]+"\t"+s[2]+"\t"+s[3]+"\t"+ s[4]); 
	                	}else             	
	        			if(rows%DataConvert.stringToInt(tips_cmd)==0){
	                		logger.debug("\n匹配中:"+s[0]+"\t"+s[1]+"\t"+s[2]+"\t"+s[3]+"\t"+ s[4]); 
	                	}
        			}
        			
            		ls_a.add(s);//添加每行数据到 ls_a
                	}
                }
            ls.add(ls_a);       //添加 每个表 到 ls            
            input.close();   
            write_Excel( xls_write_Address, ls, sheetnames ,tips_cmd)  ;                
            }            
        } catch (IOException ex) {  
            ex.printStackTrace();  
        }
        String endTmie = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        logger.debug("\n\n***************【处理完成,程序结束】***************");//7   
        logger.debug("\n开始时间:"+startTmie);
        logger.debug("\n结束时间:"+endTmie); 
        logger.debug("\n新文件输出路径为:"+xls_write_Address);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void write_Excel( String xls_write_Address,ArrayList<ArrayList> ls,String[] sheetnames,String tips_cmd ) throws IOException  {
		 
		PropertyConfigurator.configure(class_path+"log4j.properties");//获取 log4j 配置文件
		Logger logger = Logger.getLogger(Config.class ); //获取log4j的实例 		
		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]);//写入内容
            	}
    			/* CMD窗口提示方式 */
    			if(!(tips_cmd.equals("none"))&&tips_cmd!=null&&!(tips_cmd.equals(""))) {
                	if(tips_cmd.equals("all")){
                		logger.debug("\n写入中:"+s[0]+"\t"+s[1]+"\t"+s[2]+"\t"+s[3]+"\t"+ s[4]); 
                	}else             	
        			if(i%DataConvert.stringToInt(tips_cmd)==0){
                		logger.debug("\n写入中:"+s[0]+"\t"+s[1]+"\t"+s[2]+"\t"+s[3]+"\t"+ s[4]); 
                	}
    			}
            }            
         } 	
		wb.write(output);
		output.close();  	    
	}
	 
}
 




Excel文件解析--超大Excel文件读写 当我们想在Excel文件中写入100w条数据时,我们用普通的XSSFWorkbook对象写入时会发现,只有在将100w条数据全部加载入内存后才会用write()方法统一写入,这样效率很低,所以我们引入了SXSSFWorkbook进行超大Excel文件的读写。SXSSFWorkbook可以通过构造参数来控制:当数据写入内存量达到参数值时,就把这些数据flush到Excel文件中。 阅读详情

相关推荐

XSSFWorkbook,SXSSFWorkbook以及EasyExcel读取Excel文件的比较

同时读取30w数据,比较运行时间及CPU、内存占比

qq_49194330的博客 4000

JAVA使用POI(XSSFWORKBOOK)读取EXCEL文件过程解析

主要介绍了JAVA使用POI(XSSFWORKBOOK)读取EXCEL文件过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

SXSSFWorkbook高效导出海量数据报表

SXSSFWorkbook相对于XSSFWorkbook的特点就是低内存占用,SXSSFWorkbook内存里保留最新一部分的excel row,之前的以临时文件方式先写到硬盘,用硬盘空间换内存。下面是我自己在工作中封装的一个工具类 package com.cqmc.cqiop.portal.autobusinessMg.util; import org.apache.commons.lang...

浪浪的博客 1730

XSSFWorkbook读取excel模版后写入的数据过多造成OOM,使用SXSSFWorkbook解决

最近在项目中遇到这样的场景,将一批json文件(上千个)数据转为list后,按照给定的excel模版格式,填充到模版中生成最终的excel文件。但是因为json文件过多,或者json文件中转为list后的数据量过大造成了oom异常:java.lang.OutOfMemoryError:Java heap space。 原因在于XSSFWorkbook创建的 book sheet row cell 等,此时是存在内存的并没有持久化,那么随着数据量增大内存的需求量也就增大,那么很大可能就是要 ...

FinelyYang的专栏 1万+

SXSSFWorkbook操作Excel表格

SXSSFWorkbook

gugugutime.com 4549

基于POISXSSFWorkbook海量数据导出

背景 在导出Excel数据时,HSSFWorkbook和XSSFWorkbook的Excel Sheet导出条数上限(<=2003版)是65535行、256列,(>=2007版)是1048576行,16384列,如果数据量超过了此上限,就只能分sheet或者分多个Excel导出,但是还有一种方式,是没有数量限制的,那就是本文介绍的 SXSSFWorkbook了。 原理 SXSSF...

qq_37817473的博客 1486

POI操作Excel2007SXSSFWorkbook处理海量数据

原文地址:http://blog.csdn.net/little_stars/article/details/8266262

静水流深 4352

POI 海量数据/大数据文件生成SXSSFWorkbook使用简介

SXSSFWorkbook是用来生成海量excel数据文件,主要原理是借助临时存储空间生成excelPOI要求3.8以上,生成的文件格式要求是07及以上版本,因为excel07级以上版本的行数1048576,量很大,而03版本的只有6万多。 注意,实际过程中,数据承载根据数量量判断,一般用到SXSSFWorkbook,就别用list承载数据,你懂/作死。。。 当然,如果超过了1048

1万+

使用解析自定义注解和SXSSFWorkbook 实现后台导出海量数据Excel文件

使用解析自定义注解和SXSSFWorkbook 实现后台导出海量数据Excel文件

极客星云-CSDN博客 1267

POI海量数据导入

1.POI实现海量数据的导入需要相应的sql表,以及jar包 csdn: http://download.csdn.net/detail/lai13835601355/9522893 2. package test; import java.io.FileOutputStream; import java.io.IOException; import java.sql.Connection;

lai13835601355的专栏 3742

Java POI 操作读取写入 Excel

Java POI 操作读取写入 Excel 源码下载:链接: https://pan.baidu.com/s/1y7GY7NLhwbksSFoMiiOWzg 提取码:ek1z HSSF、XSSF和SXSSF区别以及Excel导出优化 一、 POI提供了HSSF、XSSF以及SXSSF三种方式操作Excel。他们的区别如下: HSSF:是操作Excel97-2003版本,扩展名为.xls...

qq_39544768的博客 846

java poi 图片 内存溢出_解决java poi海量数据导出内存溢出问题

找了很多天的解决方法,一直被分页查询绕进去了,其实数据都能查出来的,真正卡的地方是ExcelExportUtil类下调错了方法。最开始调用的方法是(标记的地方): workbook = new HSSFWorkbook();和 workbook = new XSSFWorkbook();这两个方法就是导出Excel的最关键的方法,接下来我来说说这两个方法作用:1.HSSFWorkbook:是操作...

weixin_39926016的博客 853

java poi 海量数据_JAVA使用POI导出海量数据附源码(支持图片)

实现思路简单来说就是用分页实现,每次从数据库查询部分数据,然后交给poiSXSSFWorkbookpoi发现数超过自身设置的暂存区数量时会flush到磁盘文件。所以我们需要使用poi的这个特性来实现海量数据下载。以下3个步骤:从数据库中待导出数据的总行数总行数除以页数得到查询次数循环次数将数据依次查出到SXSSFWorkbookSXSSFWorkbook中导出Excel文件附代码:1、Exc...

weixin_29157493的博客 293

poi】解决java导出excel 海量数据内存溢出问题

转自百度经验:http://jingyan.baidu.com/article/4853e1e5202c331909f72627.html那里排版忒恶心,转来这里。 由于项目中有导出海量数据的需求,在谷歌和百度也没有找到好的解决办法,经过仔细研究发现poi-3.8版本以上提供新的模式可以满足这个需求,写在这里希望能对有同样需求的同行们有所帮助。 以下是测试代码: ...

diyu8056的博客 557

EasyExcel 如何在很低的内存下导出百万条数据的 excel

SXSSFWorkbook 本身是支持导出海量数据而不至于内存溢出的, 而使用 EasyExcel 来导出xlsx文件的时候,他的底层实际使用了SXSSFWorkbook,只是做了进一步的封装,因此自然支持海量数据导出。

huachangzai的博客 1387
上一篇: 二手手机验机指南
下一篇: JspsmartUpload源码编译打包和解决乱码方法
Fantacy.
博客等级 码龄14年 53粉丝 119原创
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值