xcel2007版本的代碼以下,本文主要是用於POI解析大文件Excel容易出現內存溢出的現象而提出解決方案,故此解決了大數據量的Excel文件解析的難度,在此拿出來貢獻給你們,謝謝!html
1.Office2007與Office Open XMLjava
在Office 2007以前,Office一直都是以二進制位的方式存儲,但這種格式不易被其它軟件拿來使用,在各界的壓力下,MicroSoft於2005年發佈了基於XML的ooxml開放文檔標準。ooxml的xml schema強調減小load time,增快parsing speed,將child elements分開存儲,而不是multiple attributes一塊兒存,這有點相似於HTML的結構。ooxml 使用XML和ZIP技術結合進行文件存儲,由於XML是一個基於文本的格式,並且ZIP容器支持內容的壓縮,因此其一大優點就是能夠大大減少文件的尺寸。其它特色這裏再也不敘述。apache
2.SAX方式解析XMLapi
SAX全稱Simple API for XML,它是一個接口,也是一個軟件包。它是一種XML解析的替代方法,不一樣於DOM解析XML文檔時把全部內容一次性加載到內存中的方式,它逐行掃描文檔,一邊掃描,一邊解析。因此那些只須要單遍讀取內容的應用程序就能夠從SAX解析中受益,這對大型文檔的解析是個巨大優點。另外,SAX 「推" 模型可用於廣播環境,可以同時註冊多個ContentHandler,並行接收事件,而不是在一個管道中一個接一個地進行處理。一些支持 SAX 的語法分析器包括 Xerces,Apache parser(之前的 IBM 語法分析器)、MSXML(Microsoft 語法分析器)和 XDK(Oracle 語法分析器)。這些語法分析器是最靈活的,由於它們還支持 DOM。xss
3.POI以SAX解析excel2007文件ide
所需jar包:
poi-3.10-FINAL-20140208.jar,
poi-ooxml-3.10-FINAL-20140208.jar,
poi-ooxml-schemas-3.10-FINAL-20140208.jar
xercesImpl.jar
xml-apis-2.0.2.jar
xmlbeans-2.6.0.jar
sax2.jarfetch
package com.boguan.bte.util.excel; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.lang.StringUtils; 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; import com.boguan.bte.service.common.IExcelRowReader; import com.boguan.bte.service.common.impl.ExcelRowReader; /** * 名稱: ExcelXlsxReader.java<br> * 描述: <br> * 類型: JAVA<br> * 最近修改時間:2016年7月5日 上午10:00:52<br> * * @since 2016年7月5日 * @author 「」 */ public class ExcelXlsxReader extends DefaultHandler { private IExcelRowReader rowReader; public void setRowReader(IExcelRowReader rowReader) { this.rowReader = rowReader; } /** * 共享字符串表 */ 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; // 定義前一個元素和當前元素的位置,用來計算其中空的單元格數量,如A6和A8等 private String preRef = null, ref = null; // 定義該文檔一行最大的單元格數,用來補全一行最後可能缺失的單元格 private String maxRef = null; /** * 單元格 */ private StylesTable stylesTable; /** * 遍歷工做簿中全部的電子表格 * * @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("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 ("c".equals(name)) { // 前一個單元格的位置 if (preRef == null) { preRef = attributes.getValue("r"); } else { preRef = ref; } // 當前單元格的位置 ref = attributes.getValue("r"); // 設定單元格類型 this.setNextDataType(attributes); // Figure out if the value is an index in the SST String cellType = attributes.getValue("t"); if (cellType != null && cellType.equals("s")) { nextIsString = true; } else { nextIsString = false; } } // 當元素爲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"); String columData = attributes.getValue("r"); 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 hh:mm:ss.SSS"; } if (formatString == null) { nextDataType = CellDataType.NULL; formatString = BuiltinFormats.getBuiltinFormat(formatIndex); } } } /** * 對解析出來的數據進行類型處理 * * @param value * 單元格的值(這時候是一串數字) * @param thisStr * 一個空字符串 * @return */ @SuppressWarnings("deprecation") 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 && && StringUtils.isNotEmpty(lastContents) && StringUtils.isNumeric(lastContents)) { 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(), ""); // 補全單元格之間的空單元格 if (!ref.equals(preRef)) { int len = countNullCell(ref, preRef); for (int i = 0; i < len; i++) { rowlist.add(curCol, ""); curCol++; } } rowlist.add(curCol, value); curCol++; } else { // 若是標籤名稱爲 row ,這說明已到行尾,調用 optRows() 方法 if (name.equals("row")) { // 默認第一行爲表頭,以該行單元格數目爲最大數目 if (curRow == 0) { maxRef = ref; } // 補全一行尾部可能缺失的單元格 if (maxRef != null) { int len = countNullCell(maxRef, ref); for (int i = 0; i <= len; i++) { rowlist.add(curCol, ""); curCol++; } } rowReader.getRows(sheetIndex, curRow, rowlist); rowlist.clear(); curRow++; curCol = 0; preRef = null; ref = null; } } } /** * 計算兩個單元格之間的單元格數目(同一行) * * @param ref * @param preRef * @return */ public int countNullCell(String ref, String preRef) { // excel2007最大行數是1048576,最大列數是16384,最後一列列名是XFD String xfd = ref.replaceAll("\\d+", ""); String xfd_1 = preRef.replaceAll("\\d+", ""); xfd = fillChar(xfd, 3, '@', true); xfd_1 = fillChar(xfd_1, 3, '@', true); char[] letter = xfd.toCharArray(); char[] letter_1 = xfd_1.toCharArray(); int res = (letter[0] - letter_1[0]) * 26 * 26 + (letter[1] - letter_1[1]) * 26 + (letter[2] - letter_1[2]); return res - 1; } /** * 字符串的填充 * * @param str * @param len * @param let * @param isPre * @return */ String fillChar(String str, int len, char let, boolean isPre) { int len_1 = str.length(); if (len_1 < len) { if (isPre) { for (int i = 0; i < (len - len_1); i++) { str = let + str; } } else { for (int i = 0; i < (len - len_1); i++) { str = str + let; } } } return str; } @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; } public static void main(String[] args) { IExcelRowReader rowReader = new ExcelRowReader(); try { // ExcelReaderUtil.readExcel(rowReader, // "E://2016-07-04-011940a.xls"); System.out.println("**********************************************"); ExcelReaderUtil.readExcel(rowReader, "E://test.xlsx"); } catch (Exception e) { e.printStackTrace(); } } }