POI读取Excel文件有两种方式,一种是使用usermodel方式读取,这种方式的优势是统一接口开发,读取.xls文件的HSSFWorkbook与读取.xlsx文件的XSSFWorkbook两个类都实现了Workbook接口。另外一种是eventusermodel方式读取,这种方式比前面一种方式读取复杂很多,并且对与2003版本和2007版本的Excel处理没有统一接口,需要了解Excel的内部文件组织原理,但是效率却比第一种方式快得多,并却能轻松读取大量数据的Excel文件,而不会把内存溢出。本文也是主要介绍使用eventusermodel方式读取2007版本的Excel文件。
eventusermodel其实是使用了XML的文件格式读取Excel的,因为Excel内部组织也是通过XML实现了(可以把后缀名改为.zip)。
xl\worksheets\sheet1.xml - 第一个sheet的内容
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"><dimension ref="A1:D1"/> <sheetViews><sheetView workbookViewId="0"><selection sqref="A1:XFD1"/></sheetView></sheetViews> <sheetFormatPr defaultRowHeight="13.5" x14ac:dyDescent="0.15"/> <sheetData> <row r="1" spans="1:4" x14ac:dyDescent="0.15"> <c r="A1" t="s"><v>0</v></c> <c r="B1" t="s"><v>1</v></c> <c r="C1" t="s"><v>2</v></c> <c r="D1" t="s"><v>15</v></c> </row> </sheetData> <phoneticPr fontId="1" type="noConversion"/><pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/><pageSetup paperSize="0" orientation="portrait" horizontalDpi="0" verticalDpi="0" copies="0"/></worksheet>
<c />标签表示单元格,t=“s”,说明当前的单元格类型是字符串,那此时<v>0</v>,0则是在sharedStrings.xml的一个索引值。是<si />标签序号。
xl\sharedStrings.xml - Excel文件中字符串的值,如其内容片段
<si> <t>col1</t><phoneticPr fontId="1" type="noConversion"/> </si> <si> <t>col2</t><phoneticPr fontId="1" type="noConversion"/> </si>
POI的eventusermodel也是通过这样的原理读取Excel文件的。
首先读取Excel文件,取得XSSFReader实例:
XSSFReader reader = new XSSFReader(OPCPackage.open(file)); XMLReader xmlReader = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser"); // sharedStrings.xml实体 SharedStringsTable table = reader.getSharedStringsTable(); xmlReader.setContentHandler(new ContentHandler()//实现该接口的一个实例); InputStream sheet = reader.getSheet("rId"+sheetId); InputSourcesheetSource = new InputSource(sheet ) xmlReader.parse(sheetSource);
package net.bingosoft.import4excel.common; import java.io.File; import java.io.FileWriter; import java.io.IOException; import org.apache.commons.lang.StringUtils; import org.apache.poi.xssf.model.SharedStringsTable; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class TestContentHandler extends DefaultHandler{ private SharedStringsTable table; private boolean isString; private String value; private FileWriter writer; public TestContentHandler(SharedStringsTable table){ this.table = table; } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int) */ @Override public void characters(char[] ch, int start, int length) throws SAXException { value = new String(ch,start,length); } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#endDocument() */ @Override public void endDocument() throws SAXException { try { writer.flush(); writer.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { try { if(qName.equals("v")){ if(isString) value = table.getEntryAt(Integer.valueOf(value.trim())).getT(); writer.write(value+","); } if(qName.equals("row")){ writer.write("\r\n"); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#startDocument() */ @Override public void startDocument() throws SAXException { try { File file = new File("D:/test.txt"); if(file.exists()) file.delete(); writer = new FileWriter(file); } catch (IOException e) { e.printStackTrace(); } } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if(qName.equals("c")){ String type = attributes.getValue("t"); if(StringUtils.isNotBlank(type) && type.equals("s")){ isString = true; }else{ isString = false; } } value = ""; } }