poi解析Excel2007海量数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poi解析Excel2007海量数据相关的知识,希望对你有一定的参考价值。

  处理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

以上是关于poi解析Excel2007海量数据的主要内容,如果未能解决你的问题,请参考以下文章

java使用POI解析2007以上的Excel表格

POI读写海量Excel

poi解析excel2003和2007有没有办法是用同样的方法实现

解析xlsx文件---Java读取Excel2007

解析xlsx文件---Java读取Excel2007

Java对Excel解析(求助)