【第04篇】利用POI框架的SAX方式 之 实战心得和演示案例

      这篇文章主要是对      第01篇第02篇  网友的一些使用误区给与回复

      总结:如果你的Excel数据很少,大致2000行以下,20列以内,那么用POI的dom方式够用。

如果你的行数经常大于1w或甚至百万行,那么POI读取Excel 必须或者说只能用SAX方式,因为只有这方法不会内存溢出。

但是看到网友针对前2篇的文章,即第01篇第02篇   给与我的反馈来看,网友并没有理解它的使用方式,以及为什么构造函数要设计成如下形式:

public MyExcel2007ForPaging_high(String filename, int startRow, int endRow) throws Exception {
		if (StringUtils.isBlank(filename))
			throw new Exception("文件名不能空");
		this.filename = filename;
		this.startRow = startRow;
		this.endRow = endRow;
		processFirstSheet();
	}

       就像我开头说的,如果你的Excel数据量少,根本没必要用sax方式,那既然你用sax方式,肯定是因为文件太大,数据太多,dom方式无法读取的问题这才必须使用sax方式来读取。

    POI在dom和sax的实现上本质上不同,dom方式不管你实际获取的数据是多还是少,在读取时都是将文件全部内容读取到内存,并建立dom结构,这是最让开发人员头疼的,因为内存溢出和实际获取数据无关,只和文件大小有关;

     而sax采用直接干预读取流的方式,只获取自己需要的部分即可,这也是性能提升和不会内存溢出的原因。因为内存溢出只和实际你要获取的数据有关,和文件大小无关。那我问你,如果你实际要一次性获取10G数据,程序会报内存溢出不?当然会!因为这和poi的sax实现方式没关系,是你java虚拟机分配内存的问题!

     回到上文的构造函数,  构造函数如此设计的目的本来就不是让你一次性把Excel数据都取出来的!应该按照Excel中的总行数进行逻辑分页,一页页的读取,首先针对每页进行处理业务逻辑,之后释放内存,然后读取下一页的数据...以此类推...这样就能保证内存中只有一页的数据函数等待处理,而不是全部数据全部弄到内存。

     那么,上两篇的文章的函数如何使用呢?或者说如何将文件的数据进行逻辑分页呢?

    下面贴出我们项目使用的分页接口,函数名称见名知义,不多解释。能用则用,不能用,聪明的网友就自己写吧。^_^

代码里涉及了MyExcel2007ForMaxRow 、MyExcel2007ForPaging_high这两个类,这里不贴了,在前面3篇文章里有贴的。

 

import java.io.File;
import java.util.LinkedList;
import java.util.List;

public class SaxPOI2 {
	private  static SaxPOI2 instance = null;
	public final static int TITLELINE_ROW_INDEX = 0;
	
	private SaxPOI2() {

	}
	public static SaxPOI2 getInstance() {
		if(instance==null){
			instance = new SaxPOI2();
		}
		return instance;
	}

	
	/**
	 * 获取文件标题
	 * @param file
	 * @param rows
	 * @return
	 * @throws Exception
	 */
	public static List<List<String>> getTitles(File file,int sumOfrows) throws Exception{
		//由于这里标题就是具体内容,所以应该把标题当做要获取的数据
		return SaxPOI2.getPagingData(file, 1, sumOfrows, sumOfrows,0);
	}

	/**
	 * 利用POI的sax方式分页读取2007的Excel
	 * 
	 * @param file
	 * @param page 页号 从1开始
	 * @param rows 页内行数
	 * @param totalRows 实际的总行数(去除标题)
	 * @param outOfTitleRow 忽略标题行的行数,负数忽略,0代表包含标题,正值代表跳过的标题数
	 * @return
	 * @throws Exception
	 */
	public  static  List<List<String>> getPagingData(File file, int page,
			int rows,int totalRows,int outOfTitleRow) throws Exception {

		// 总记录行数(除去标题)
		int sumOfRows = totalRows;

		// SAX解析方式第一行是1,不是0
		int headLineRowNum = SaxPOI2.TITLELINE_ROW_INDEX;
		if(outOfTitleRow>0){
			headLineRowNum += outOfTitleRow;
		}
		// 循环的默认起始和结束
		int startRow = headLineRowNum + 1;
		int endRow = startRow + rows - 1;
		// 最后一行的行号
		int lastRowNum = sumOfRows + headLineRowNum;
		int odd = sumOfRows - ((page - 1) * rows);// 本页之前的所有记录
		if ((page - 1) * rows >= sumOfRows) {// 本页之前的所有记录已经超过总数了
			return new LinkedList<List<String>>();
		} else if (odd > 0 && odd <= rows) {// 剩下的行数不够本页显示数

			startRow = (headLineRowNum + 1) + (page - 1) * rows;
			endRow = lastRowNum;
		} else {// 所剩行数充足
			startRow = headLineRowNum + (page - 1) * rows + 1;
			endRow = headLineRowNum + page * rows;
		}

		return new MyExcel2007ForPaging_high(file.getPath(), startRow, endRow).getMyDataList();
	}
	
	
	/**
	 * 采用SAX读取2007版的xlsx形式的Excel的最大行
	 * 
	 * @param f
	 * @return
	 * @throws Exception
	 */
	public static long getSize4TheFile(File f) throws Exception {
		
		MyExcel2007ForMaxRow reader = new MyExcel2007ForMaxRow(f);
		return reader.maxRow - (SaxPOI2.TITLELINE_ROW_INDEX + 1);

	}

	
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值