处理excel,开源的javaApI提供了两种,一种是jxl,一种是poi。poi提供的功能较多,所以我用的是poi。
poi有两种模式,一个是用户模式(HSSFworkbook:支持Excel2003,XSSFworkbook:支持Excel2007),这个操作数量上万的时候会造成out of memory 的情况。另一个是事件驱动模,解析的Excel数据上万的时候用这个,这里拿Excel2007来说明,Excel2007的底层其实就是xml形式的,其实也就是解析xml。
底层xml格式:
<sheetData>//代表一个shet - <row r="1" spans="1:33">//代表一个行 - <c r="A1" t="s">//代表一个单元格 r是坐标 <v>0</v> //代表相应的值,这里的0不是真正的值 </c> - <c r="B1" t="s"> <v>1</v> </c> - <c r="C1" t="s"> <v>2</v> </c> </row> </sheetData>
所需jar包:poi.jar,poi-excelant,poi-ooxml.jar,poi-ooxml-schemas.jar,poi- scratchpad.jar,dom4j.jar,xmlbeans.jar,xerces.jar
代码:空值问题待解决
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.xssf.eventusermodel.ReadOnlySharedStringsTable; import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.model.StylesTable; 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; //Default是sax解析xml的处理类 public class TestExcel2007Util{ public static void main(String[] args) throws IOException, OpenXML4JException, SAXException { Excel2007Util excel2007Util=new Excel2007Util(); excel2007Util.process("C:/Users/sime/Desktop/XXX.xlsx"); } } class Excel2007Util extends DefaultHandler{ //共享字符串表 private ReadOnlySharedStringsTable sst; //单元格 private StylesTable stylesTable; private String lastContents; private boolean nextIsString; private List<String> rowlist=new ArrayList<String>(); //当前页 private int sheetIndex; //当前行 private int curRow =0; //当前单元格 private int curCol =0; private boolean cellNull; /** * excel记录行操作方法,rowlist是一行记录,这里可以进行你的逻辑处理 */ public void optRows(int sheetIndex,int curRow,List<String> rowlist){ System.out.println(rowlist.toString()); } /** * 遍历工作簿中所有的电子表格 * @throws OpenXML4JException * @throws IOException * @throws SAXException */ public void process (String filename) throws IOException, OpenXML4JException, SAXException{ OPCPackage pkg = OPCPackage.open(filename); XSSFReader xssfReader = new XSSFReader(pkg); sst = new ReadOnlySharedStringsTable(pkg); 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(); } pkg.close(); } public XMLReader fetchSheetParser(ReadOnlySharedStringsTable sst) throws SAXException { XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
parser.setContentHandler(this);
return parser; } /** * 解析器在 XML 文档中的每个元素的开始调用此方法 * uri:名称空间 URI * localName:本地名称 * name:限定名 * attributes:连接到元素上的属性 */ public void startElement(String uri, String localName, String name, Attributes attributes){ if (name.equals("c")) { // 如果下一个元素是 SST 的索引,则将nextIsString标记为true String cellType = attributes.getValue("t"); // System.out.println("cellType : " + cellType); if (cellType != null && cellType.equals("s")) { nextIsString = true; cellNull = false; } else { nextIsString = false; cellNull = true; } } lastContents = ""; } // 根据SST的索引值的到单元格的真正要存储的字符串 // 这时characters()方法可能会被调用多次 public void characters(char[] ch, int start, int length) throws SAXException { //得到单元格内容的值 lastContents += new String(ch, start, length); } public void endElement (String uri, String localName, String name){ 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") || "t".equals(name)) { String value = lastContents.trim(); rowlist.add(curCol, value); curCol++; cellNull = false; }else if("c".equals(name)){ rowlist.add(curCol, ""); curCol++; cellNull = false; }else { //如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法 if (name.equals("row")) { optRows(sheetIndex,curRow,rowlist); rowlist.clear(); curRow++; curCol = 0; } } } }
这是个人网上百度后总结的方法,比较简洁,可以直接拿去用,但是空值的问题尚未解决,如有不对的地方请指出。
org.apache.xerces.parsers.SAXParser