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 = "";
}
}