`

读取大数据量excel

    博客分类:
  • java
阅读更多
package excel;


import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
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;


public class Excel2007Reader 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;


	/**
	* T元素标识
	*/
	private boolean isTElement;


	/**
	* 异常信息,如果为空则表示没有异常
	*/
	private String exceptionMessage;


	/**
	* 单元格数据类型,默认为字符串类型
	*/
	private CellDataType nextDataType = CellDataType.SSTINDEX;


	private final DataFormatter formatter = new DataFormatter();


	private short formatIndex;


	private String formatString;
	/** 封装第一行的标题信息,防止空单元格 */
	private List<String> title = new ArrayList<String>();


	/**
	* 单元格
	*/
	private StylesTable stylesTable;


	/**
	* 取第一个sheet里内容
	* 
	* @param filename
	* @param sheetId
	* @throws Exception
	*/
	public void processOneSheet(String filename, int sheetId) throws Exception {
		OPCPackage pkg = OPCPackage.open(filename);
		XSSFReader xssfReader = new XSSFReader(pkg);
		stylesTable = xssfReader.getStylesTable();
		SharedStringsTable sst = xssfReader.getSharedStringsTable();
		XMLReader parser = this.fetchSheetParser(sst);
		InputStream sheet = xssfReader.getSheet("rId" + sheetId);
		sheetIndex++;
		InputSource sheetSource = new InputSource(sheet);
		parser.parse(sheetSource);
		sheet.close();
	}


	/**
	* 遍历工作簿中所有的电子表格
	* 
	* @param filename
	* @throws IOException
	* @throws OpenXML4JException
	* @throws SAXException
	* @throws Exception
	*/
	public void process(String filename) throws IOException,OpenXML4JException, SAXException {
		OPCPackage pkg = OPCPackage.open(filename);
		XSSFReader xssfReader = new XSSFReader(pkg);
		stylesTable = xssfReader.getStylesTable();
		SharedStringsTable sst = xssfReader.getSharedStringsTable();
		XMLReader parser = this.fetchSheetParser(sst);
		Iterator<InputStream> sheets = xssfReader.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();
		// XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
		this.sst = sst;
		parser.setContentHandler(this);
		return parser;
	}


	/**
	* 模板中有多少列就设置多少列
	* 
	* @author Administrator
	* 
	*/
	enum TitleItem {
		A("A"), B("B"), C("C"), D("D"), E("E"), F("F"), G("G"), H("H"), I("I"), J("J");
		private String key;


		TitleItem(String key) {
			this.key = key;
		}


		public static TitleItem getObj(String key) {
			for (TitleItem obj : values()) {
				if (obj.getKey().equals(key)) {
					return obj;
				}
			}
			return null;
		}


		public String getKey() {
			return key;
		}


		public void setKey(String key) {
			this.key = key;
		}


	}


	@Override
	public void startElement(String uri, String localName, String name,	Attributes attributes) throws SAXException {
		// 封装title
		String type = attributes.getValue("r");
		if (type != null && !type.equals("")) {
			type = type.substring(0, 1);
			if (TitleItem.getObj(type) != null) {
				title.add(type);
			}
		}


		// c => 单元格
		if ("c".equals(name)) {
			// 设定单元格类型
			this.setNextDataType(attributes);
		}


		// 当元素为t时
		if ("t".equals(name)) {
			isTElement = true;
		} else {
			isTElement = false;
		}
		// 置空
		lastContents = "";
	}


	/**
	* 单元格中的数据可能的数据类型
	*/
	enum CellDataType {
		BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER, DATE, NULL
	}


	/**
	* 处理数据类型
	* 
	* @param attributes
	*/
	public void setNextDataType(Attributes attributes) {
		nextDataType = CellDataType.NUMBER;
		formatIndex = -1;
		formatString = null;
		String cellType = attributes.getValue("t");
		String cellStyleStr = attributes.getValue("s");


		if ("b".equals(cellType)) {
			nextDataType = CellDataType.BOOL;
		} else if ("e".equals(cellType)) {
			nextDataType = CellDataType.ERROR;
		} else if ("inlineStr".equals(cellType)) {
			nextDataType = CellDataType.INLINESTR;
		} else if ("s".equals(cellType)) {
			nextDataType = CellDataType.SSTINDEX;
		} else if ("str".equals(cellType)) {
			nextDataType = CellDataType.FORMULA;
		}


		if (cellStyleStr != null) {
			int styleIndex = Integer.parseInt(cellStyleStr);
			XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
			formatIndex = style.getDataFormat();
			formatString = style.getDataFormatString();


			if ("m/d/yy" == formatString) {
				nextDataType = CellDataType.DATE;
				formatString = "yyyy-MM-dd";
				// formatString = "yyyy-MM-dd hh:mm:ss.SSS";
			}


			if (formatString == null) {
				nextDataType = CellDataType.NULL;
				formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
			}
		}
	}


	/**
	* 对解析出来的数据进行类型处理
	* 
	* @param value
	*            单元格的值(这时候是一串数字)
	* @param thisStr
	*            一个空字符串
	* @return
	*/
	public String getDataValue(String value, String thisStr) {
		switch (nextDataType) {
		// 这几个的顺序不能随便交换,交换了很可能会导致数据错误
		case BOOL:
			char first = value.charAt(0);
			thisStr = first == '0' ? "FALSE" : "TRUE";
			break;
		case ERROR:
			thisStr = "\"ERROR:" + value.toString() + '"';
			break;
		case FORMULA:
			thisStr = '"' + value.toString() + '"';
			break;
		case INLINESTR:
			XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());


			thisStr = rtsi.toString();
			rtsi = null;
			break;
		case SSTINDEX:
			String sstIndex = value.toString();
			try {
				int idx = Integer.parseInt(sstIndex);
				XSSFRichTextString rtss = new XSSFRichTextString(sst.getEntryAt(idx));
				thisStr = rtss.toString();
				rtss = null;
			} catch (NumberFormatException ex) {
				thisStr = value.toString();
			}
			break;
		case NUMBER:
			if (formatString != null) {
				thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString).trim();
			} else {
				thisStr = value;
			}


			thisStr = thisStr.replace("_", "").trim();
			break;
		case DATE:
			thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString);


			// 对日期字符串作特殊处理
			thisStr = thisStr.replace(" ", "T");
			break;
		default:
			thisStr = " ";


			break;
		}


		return thisStr;
	}


	@Override
	public void endElement(String uri, String localName, String name) throws SAXException {


		// 根据SST的索引值的到单元格的真正要存储的字符串
		// 这时characters()方法可能会被调用多次
		if (nextIsString) {
			int idx = Integer.parseInt(lastContents);
			lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
		}


		// t元素也包含字符串
		if (isTElement) {
			// 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
			String value = lastContents.trim();
			rowlist.add(curCol, value);
			curCol++;
			isTElement = false;
		} else if ("v".equals(name)) {
			// v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引
			String value = this.getDataValue(lastContents.trim(), "");


			rowlist.add(curCol, value);
			curCol++;
		} else {
			// 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法
			if (name.equals("row")) {
				try {
					// 一行信息结束时进行业务逻辑处理
					optRow(sheetIndex, curRow, rowlist, title);
					// 重置当前行标题信息
					title = new ArrayList<String>();
				} catch (Exception e) {
					e.printStackTrace();
				}
				rowlist.clear();
				curRow++;
				curCol = 0;
			}
		}
	}


	/**
	* 处理每一行数据,可以根据业务需要封装成业务实体(每一行都保证有全部单元格的内容,空单元格内容为“”)
	* 
	* @param sheetIndex
	* @param curRow
	* @param rowList
	* @param title
	*/
	public void optRow(int sheetIndex, int curRow, List<String> rowList,List<String> title) {
		System.out.println("第 " + (curRow + 1) + " 行数据如下:");
		List<String> list = changeList(rowList, title);
		for (String string : list) {
			System.out.println(string);
		}
		/*
		* System.out.println("---------------------------------------"); for
		* (String key : title) { System.out.println(key); }
		* System.out.println("第 "+(curRow+1)+" 行数据如下:"); for (int i = 0; i <
		* rowlist.size(); i++) { System.out.print("'" + rowlist.get(i) + "',");
		* } System.out.println("\n---------------------------------------");
		*/
	}


	/**
	* 将为空的单元内容读取出来(上面方法无法取到空单元格,所以人工处理一下)
	* 
	* @param rowList
	* @param title
	*/
	public List<String> changeList(List<String> rowList, List<String> title) {
		TitleItem[] titles = TitleItem.values();
		// 共有多少个字段
		int count = titles.length;
		// 实际有多少个字段
		int realCount = title.size();
		List<String> result = rowList;
		// 有空单元格
		if (count != realCount) {
			result = new ArrayList<String>();
			for (int i = 0; i < count; i++) {
				boolean flag = false;
				String value = "";
				for (int j = 0; j < realCount; j++) {
					// 和单元格标题匹配,不存在内容为“”
					flag = title.get(j).equals(titles[i].getKey()) ? true : false;
					if (flag) {
						value = rowlist.get(j);
						break;
					}
				}
				result.add(value);
			}
		}
		return result;
	}


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


	/**
	* @return the exceptionMessage
	*/
	public String getExceptionMessage() {
		return exceptionMessage;
	}
}
分享到:
评论

相关推荐

    使用Poi读取大数据量excel的方法

    本篇文章将详细讲解如何利用Apache POI库在Android环境中高效地处理大数据量的Excel文件,无论是2003的.xls格式还是2007及以后的.xlsx格式。 首先,我们需要在项目中引入Apache POI库。如果是Maven项目,可以在pom....

    poi读取大数据量excel文件,避免内存溢出,行级操作

    poi读取大数据量excel文件,避免内存溢出,行级操作 根据本网站的资源修改的。 将一些类路径错误全部进行了修正。 另外,需要自己在类路径里,放spring-context.jar和spring-beans.jar包。

    Java读取大数据量Excel的方法(POI)

    接下来,我们将详细讲解如何使用Apache POI读取大数据量的Excel文件: 1. **创建Workbook对象**:这是处理Excel文件的基础,它代表整个Excel工作簿。你可以通过`XSSFWorkbook`类的构造函数,传入文件的输入流来创建...

    大数据量Excel07版表格文件导入时,快速有效读取数据工具类

    此工具类是基于Apache POI的用于读取大数据量Excel 07版后的表格文件,从而高效地读取到表格数据并以集合形式保存下来。 使用方式: List[]&gt; list = new ArrayList[]&gt;(); ExcelXlsxParser parser = new ...

    excle大量数据读取

    在Excel处理大量数据时,传统的读取方法可能会面临性能瓶颈,尤其是在数据量达到10万条甚至更多时,常见的操作可能导致内存溢出,严重影响程序的稳定性和效率。为了解决这个问题,我们需要采用优化的策略来读取和...

    读取大数据量的excel文件

    usermodel模式对excel操作前需要将文件全部转入内存,对较大文件来说内存开销很大。但是其使用简单。 eventusermodel模式采用事件模型,对文件边读取边处理,内存消耗较低,效率高,因为不用等待文件全部装入内存。...

    Android Excel文件写入和读取

    - 遍历行和单元格:通过工作表的`getRow`方法获取行,再通过行的`getCell`方法获取单元格,从而读取数据。 - 关闭流:读取完成后,记得关闭输入流,以释放资源。 4. **处理大数据**:当处理大量数据时,应考虑...

    Java解析大数据量Excel,可解析1048576行excel

    在处理大数据量的Excel文件时,Java是一种常用的语言,因为它提供了强大的库,如Apache POI,使得解析大型Excel文件成为可能。Apache POI是Java的一个开源项目,专门用于读写Microsoft Office格式的文件,包括Excel...

    使用Poi读取大数据量excel的方法-Java代码类资源

    本资源“使用Poi读取大数据量excel的方法”提供了处理大量数据时使用POI进行有效读取的示例代码。以下是关于如何使用POI高效地处理大数据量Excel文件的一些关键知识点: 1. **POI组件**: - HSSF:处理Excel 97-...

    读取百万级数据量的xlsx文件的java代码

    该代码可以处理100万数据量的excel文件,xlsx文件数据量太大,用普通的读法会报内存溢出错误,所以用官网提供的方法,一条一条的读取大excel文件,本例子从这点出发,组装excel里读取的单条数据为list,在根据需求...

    Android开发之读取Excel表格数据

    - **数据库存储**:如果数据量大,可以考虑将读取的数据存储到SQLite数据库,便于后续查询和使用。 - **界面展示**:将数据绑定到RecyclerView或ListView等组件上,实现数据的动态展示。 总之,通过使用Android的...

    Excel大量数据快速导入数据库源码

    标题 "Excel大量数据快速导入数据库源码" 描述的是一个编程解决方案,用于高效地将Excel电子表格中的大量数据批量导入到数据库系统中。这个过程通常涉及到数据预处理、数据清洗和数据传输等步骤,是数据处理工作流程...

    looly#hutool-site#流方式读取Excel2003-Excel03SaxReader1

    介绍在标准的ExcelReader中,如果数据量较大,读取Excel会非常缓慢,并有可能造成内存溢出。因此针对大数据量的Excel,Hutool封装了event

    java poi 导入大数据量Excel数据 防止内存溢出处理.zip

    然而,当处理大数据量的Excel文件时,POI可能会导致内存溢出(Out of Memory, OOM),因为默认情况下它会将整个工作簿加载到内存中。为了防止这种问题,我们需要采用优化策略来高效地处理大量数据。 1. **分块读取*...

    大数据量Excel读取工具.zip

    大数据量Excel读取工具maven_excel_util大数据量Excel读取工具

    C#中读取Excel表格数据实例

    ExcelDataReader是一个轻量级的只读库,它可以直接读取Excel二进制流,性能高效。 在实际项目中,选择哪种方法取决于具体需求,如是否需要安装额外的驱动、对性能的要求、文件格式兼容性以及功能复杂度等因素。如果...

    QtExcel.rar_QT操作ex_Qt 表格_qt 数据 excel_qt读取excel表格_qt读取表格

    QtExcel项目正是为了提供这种功能,使开发者能够在Qt环境中方便地操作Excel文档,特别是处理大量数据时。本文将详细介绍如何使用Qt进行Excel操作,并探讨相关的关键知识点。 1. **Qt库与QAxContainer模块** Qt是一...

    直接读取Excel文件数据

    ### 直接读取Excel文件数据 #### 一、引言 Microsoft Excel 是一款非常流行的电子表格处理软件,被广泛应用于各种...这种技术对于那些需要处理大量 Excel 数据的应用程序开发非常重要,能够极大地提高数据处理的效率。

    Unity数据 ExcelData 读取包

    Unity数据ExcelData读取包是一种在Unity开发过程中用于处理和读取Excel数据的工具或库。这个包的主要目的是简化游戏开发中的数据管理,特别是在需要大量使用表格数据的情况下,如角色属性、道具配置、地图信息等。...

Global site tag (gtag.js) - Google Analytics