Java读取操作大数据excel

工作需要,读取大数据量的excel。用Apache poi的普通模式读取,会抛内存溢出。查询文档得知有另外一种模式--用户模式。该模式不会一下子整个文件load进来放在内存里,而是一行一行的读取,这样就能避免内存溢出了。

上码:

package com.ism.excel.pkg07;

import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 * XSSF and SAX (Event API)
 */
public abstract class XxlsAbstract extends DefaultHandler {
	private SharedStringsTable sst;
	private String lastContents;
	private boolean nextIsString;

	private int sheetIndex = -1;
	private List<String> rowlist = new ArrayList<String>();
	private int curRow = 0;		//当前行
	private int curCol = 0;		//当前列索引
	private int preCol = 0;		//上一列列索引
	private int titleRow = 0;	//标题行,一般情况下为0
	private int rowsize = 0;	//列数

	//excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型
	public abstract void optRows(int sheetIndex,int curRow, List<String> rowlist) throws SQLException;

	//只遍历一个sheet,其中sheetId为要遍历的sheet索引,从1开始,1-3
	/**
	 *
	 * @param filename
	 * @param sheetId  sheetId为要遍历的sheet索引,从1开始,1-3
	 * @throws Exception
	 */
	public void processOneSheet(String filename,int sheetId) throws Exception {
		OPCPackage pkg = OPCPackage.open(filename);
		XSSFReader r = new XSSFReader(pkg);
		SharedStringsTable sst = r.getSharedStringsTable();

		XMLReader parser = fetchSheetParser(sst);

		// rId2 found by processing the Workbook
		// 根据 rId# 或 rSheet# 查找sheet
		InputStream sheet2 = r.getSheet("rId"+sheetId);
		sheetIndex++;
		InputSource sheetSource = new InputSource(sheet2);
		parser.parse(sheetSource);
		sheet2.close();
	}

	/**
	 * 遍历 excel 文件
	 */
	public void process(String filename) throws Exception {
		OPCPackage pkg = OPCPackage.open(filename);
		XSSFReader r = new XSSFReader(pkg);
		SharedStringsTable sst = r.getSharedStringsTable();

		XMLReader parser = fetchSheetParser(sst);

		Iterator<InputStream> sheets = r.getSheetsData();
		while (sheets.hasNext()) {
			curRow = 0;
			sheetIndex++;
			InputStream sheet = sheets.next();
			InputSource sheetSource = new InputSource(sheet);
			parser.parse(sheetSource);
			sheet.close();
		}
	}

	public XMLReader fetchSheetParser(SharedStringsTable sst)
			throws SAXException {
		XMLReader parser = XMLReaderFactory.createXMLReader();
				//.createXMLReader("org.apache.xerces.parsers.SAXParser");
		this.sst = sst;
		parser.setContentHandler(this);
		return parser;
	}

	public void startElement(String uri, String localName, String name,
			Attributes attributes) throws SAXException {
		// c => 单元格
		if (name.equals("c")) {
			// 如果下一个元素是 SST 的索引,则将nextIsString标记为true
			String cellType = attributes.getValue("t");
			String rowStr = attributes.getValue("r");
			curCol = this.getRowIndex(rowStr);
			if (cellType != null && cellType.equals("s")) {
				nextIsString = true;
			} else {
				nextIsString = false;
			}
		}
		// 置空
		lastContents = "";
	}

	public void endElement(String uri, String localName, String name)
			throws SAXException {
		// 根据SST的索引值的到单元格的真正要存储的字符串
		// 这时characters()方法可能会被调用多次
		if (nextIsString) {
			try {
				int idx = Integer.parseInt(lastContents);
				lastContents = new XSSFRichTextString(sst.getEntryAt(idx))
						.toString();
			} catch (Exception e) {

			}
		}

		// v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引
		// 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
		if (name.equals("v")) {
			String value = lastContents.trim();
			value = value.equals("")?" ":value;
			int cols = curCol-preCol;
			if (cols>1){
				for (int i = 0;i < cols-1;i++){
					rowlist.add(preCol,"");
				}
			}
			preCol = curCol;
			rowlist.add(curCol-1, value);
		}else {
			//如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法
			if (name.equals("row")) {
				int tmpCols = rowlist.size();
				if(curRow>this.titleRow && tmpCols<this.rowsize){
					for (int i = 0;i < this.rowsize-tmpCols;i++){
						rowlist.add(rowlist.size(), "");
					}
				}
				try {
					optRows(sheetIndex,curRow,rowlist);
				} catch (SQLException e) {
					e.printStackTrace();
				}
				if(curRow==this.titleRow){
					this.rowsize = rowlist.size();
				}
				rowlist.clear();
				curRow++;
				curCol = 0;
				preCol = 0;
			}
		}
	}

	public void characters(char[] ch, int start, int length)
			throws SAXException {
		//得到单元格内容的值
		lastContents += new String(ch, start, length);
	}

	//得到列索引,每一列c元素的r属性构成为字母加数字的形式,字母组合为列索引,数字组合为行索引,
	//如AB45,表示为第(A-A+1)*26+(B-A+1)*26列,45行
	public int getRowIndex(String rowStr){
		rowStr = rowStr.replaceAll("[^A-Z]", "");
		byte[] rowAbc = rowStr.getBytes();
		int len = rowAbc.length;
		float num = 0;
		for (int i=0;i<len;i++){
			num += (rowAbc[i]-'A'+1)*Math.pow(26,len-i-1 );
		}
		return (int) num;
	}

	public int getTitleRow() {
		return titleRow;
	}

	public void setTitleRow(int titleRow) {
		this.titleRow = titleRow;
	}
}
时间: 2024-11-29 03:27:15

Java读取操作大数据excel的相关文章

java面试(2)--大数据相关

第一部分.十道海量数据处理面试题 1.海量日志数据,提取出某日访问百度次数最多的那个IP. 首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中.注意到IP是32位的,最多有个2^32个IP.同样可以采用映射的方法, 比如模1000,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进行频率统计,然后再找出频率最大 的几个)及相应的频率.然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求. 或者如下阐述(雪域之鹰)

LZ从Java Web转大数据,并且成功拿到上市公司Offer,工资直接涨了9K+

Before 本文的目的是为你(有一定编程基础的同学仔)提供一些想打算转大数据的参考: 如果你是大数据工程师,不太适合你进行进阶学习: 如果你是零编程基础同学仔,你可以参考我之前写的blog,建议先把基础打牢,再去学习大数据: 如果你不是攻城狮,那么你可以当做一个故事即可. 大家好,我是Hongten 今天我要给大家分享一下我的个人经历,我从Java Web转大数据,并且成功拿到上市公司Offer,工资直接涨了9K+ 我大二的时候,就开始接触Java,之前也接触了一些Android的知识,但是最

Java编程语言开发大数据的优势有哪些?

Java编程语言开发大数据的优势有哪些?Java语言支持各类组件.Java在物联网方面应用.Java移动领域应用.Java支撑超级计算机设备.GPU成为大多数速度最快的超级计算设备所不可或缺的处理器.Java“一次编写随处起效”架构技术能够在工作站上开发自己的软件移植到系统当中. Java编程语言开发大数据的优势: 一.Java支持各类组件 Java版本不断更新,使Java具备更出色的模块化特性.有多种“接入并起效”架构供选择,进一步拓展Java的传统编程模式.性能可扩展能力.模块的出现能够对结

Java在处理大数据的时候一些小技巧

转载自:http://soft.chinabyte.com/database/258/12609258.shtml 众所周知,java在处理数据量比较大的时候,加载到内存必然会导致内存溢出,而在一些数据处理中我们不得不去处理海量数据,在做数据处理中,我们常见的手段是分解,压缩,并行,临时文件等方法; 例如,我们要将数据库(不论是什么数据库)的数据导出到一个文件,一般是Excel或文本格式的CSV;对于Excel来讲,对于POI和JXL的接口,你很多时候没有办法去控制内存什么时候向磁盘写入,很恶心

Java数据库——处理大数据对象

处理大数据对象 CLOB中可以存储海量文字 BLOB中可以存储海量二进制数据 如果程序中要想处理这样的大对象操作,则必须使用PreparedStatement完成,所有的内容要通过IO流的方式从大文本字段中保存和读取. 写入大文本数据 汉字的编码要改成gbk //================================================= // File Name : Clob_demo //-----------------------------------------

JAVA IO操作:数据操作流:DataOutputStream和DataInputStream

掌握DataOutputStream和DataInputStream的作用. 可以使用DataOutputStream和DataInputStream写入和读取数据. 在IO包中提供了两个与平台无关的数据操作流 数据输出流:DataOutputStream 数据输入流:DataInputStream 通常按照一定格式将输入输出,再按照一定格式将数据输入. 要想使用数据输出流和输入流,则肯定要用户指定数据的保存格式.必须按指定的格式保存数据,才可以将数据输入流将数据读取进来. DataOutput

阿里年薪50万的JAVA工程师转大数据学习路线

大数据有两个方向,一个是偏计算机的,另一个是偏经济的.你学过Java,所以你可以偏将计算机的. Java程序员想转大数据可行吗?Java是全世界使用人数最多的编程语言.不少程序员选择Java做为了自己的编程第一语言,但随之而来的是Java程序员接近饱和的人才市场.由此,随着大数据时代的到来,有很多Java程序员想要转行大数据. 不得不说,大数据行业可以说是为Java程序员量身打造的一个朝阳行业?为什么要这么说呢? 互联网是当下流行趋势,且未来可期.大数据的发展亦是时代发展的必然,如果大家还想要了

Java Array和大数据运算

1.Array类 ?sort方法,用来对指定数组中的元素进行排序(元素值从小到大进行排序) //源arr数组元素{1,5,9,3,7}, 进行排序后arr数组元素为{1,3,5,7,9} int[] arr = {1,5,9,3,7}; Arrays.sort( arr ); ?toString方法,用来返回指定数组元素内容的字符串形式 int[] arr = {1,5,9,3,7}; String str = Arrays.toString(arr); // str的值为[1, 3, 5, 7

java开发转行大数据开发的学习路径

从Java开发通过大概3个月的学习转到大数据开发,主要分享一下学习路径: 第一阶段: 01.Linux学习(跟鸟哥学就ok了) 02.Java 高级学习(<深入理解Java虚拟机>.<Java高并发实战>) 第二阶段: 03.Hadoop (董西成的书) 04.HBase(<HBase权威指南>) 05.Hive(<Hive开发指南>) 06.Scala(<快学Scala>) 07.Spark (<Spark 快速大数据分析>) 08