Java读取大数据量07Excel的方法(POI)


工作当中遇到要读取大数据量Excel(10万行以上,Excel 2007),用POI方式读取,用HSSFWorkbook读取时,超过2万行JVM的内存就会溢出,在网上找到原来要用XML方式逐行读取,记录下来,以供参考。

    注意:运行环境是jdk1.6,如果要在1.5的环境中运行,要把jdk1.6中的rt.jar中javax.xml包下所有类加到运行的环境中。

    下面是代码:

  1. import java.io.InputStream;    
  2. import java.util.ArrayList;    
  3. import java.util.Iterator;    
  4. import java.util.List;    
  5.    
  6. import org.apache.poi.openxml4j.opc.OPCPackage;    
  7. import org.apache.poi.xssf.eventusermodel.XSSFReader;    
  8. import org.apache.poi.xssf.model.SharedStringsTable;    
  9. import org.apache.poi.xssf.usermodel.XSSFRichTextString;    
  10. import org.xml.sax.Attributes;    
  11. import org.xml.sax.InputSource;    
  12. import org.xml.sax.SAXException;    
  13. import org.xml.sax.XMLReader;    
  14. import org.xml.sax.helpers.DefaultHandler;    
  15. import org.xml.sax.helpers.XMLReaderFactory;    
  16.    
  17. public class ExcelUtil extends DefaultHandler {    
  18.         
  19.     private SharedStringsTable sst;    
  20.     private String lastContents;    
  21.     private boolean nextIsString;    
  22.    
  23.     private int sheetIndex = -1;    
  24.     private List<String> rowlist = new ArrayList<String>();    
  25.     private int curRow = 0;    
  26.     private int curCol = 0;    
  27.         
  28.         
  29.     /** 
  30.      * 读取第一个工作簿的入口方法 
  31.      * @param path 
  32.      */    
  33.     public void readOneSheet(String path) throws Exception {    
  34.         OPCPackage pkg = OPCPackage.open(path);         
  35.         XSSFReader r = new XSSFReader(pkg);    
  36.         SharedStringsTable sst = r.getSharedStringsTable();    
  37.                 
  38.         XMLReader parser = fetchSheetParser(sst);    
  39.                 
  40.         InputStream sheet = r.getSheet("rId1");    
  41.    
  42.         InputSource sheetSource = new InputSource(sheet);    
  43.         parser.parse(sheetSource);    
  44.                 
  45.         sheet.close();          
  46.     }    
  47.         
  48.         
  49.     /** 
  50.      * 读取所有工作簿的入口方法 
  51.      * @param path 
  52.      * @throws Exception 
  53.      */    
  54.     public void process(String path) throws Exception {    
  55.         OPCPackage pkg = OPCPackage.open(path);    
  56.         XSSFReader r = new XSSFReader(pkg);    
  57.         SharedStringsTable sst = r.getSharedStringsTable();    
  58.    
  59.         XMLReader parser = fetchSheetParser(sst);    
  60.    
  61.         Iterator<InputStream> sheets = r.getSheetsData();    
  62.         while (sheets.hasNext()) {    
  63.             curRow = 0;    
  64.             sheetIndex++;    
  65.             InputStream sheet = sheets.next();    
  66.             InputSource sheetSource = new InputSource(sheet);    
  67.             parser.parse(sheetSource);    
  68.             sheet.close();    
  69.         }    
  70.     }    
  71.         
  72.     /** 
  73.      * 该方法自动被调用,每读一行调用一次,在方法中写自己的业务逻辑即可 
  74.      * @param sheetIndex 工作簿序号 
  75.      * @param curRow 处理到第几行 
  76.      * @param rowList 当前数据行的数据集合 
  77.      */    
  78.     public void optRow(int sheetIndex, int curRow, List<String> rowList) {    
  79.         String temp = "";    
  80.         for(String str : rowList) {    
  81.             temp += str + "_";    
  82.         }    
  83.         System.out.println(temp);    
  84.     }    
  85.         
  86.         
  87.     public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException {    
  88.         XMLReader parser = XMLReaderFactory    
  89.                 .createXMLReader("org.apache.xerces.parsers.SAXParser");    
  90.         this.sst = sst;    
  91.         parser.setContentHandler(this);    
  92.         return parser;    
  93.     }    
  94.         
  95.     public void startElement(String uri, String localName, String name,    
  96.             Attributes attributes) throws SAXException {    
  97.         // c => 单元格    
  98.         if (name.equals("c")) {    
  99.             // 如果下一个元素是 SST 的索引,则将nextIsString标记为true    
  100.             String cellType = attributes.getValue("t");    
  101.             if (cellType != null && cellType.equals("s")) {    
  102.                 nextIsString = true;    
  103.             } else {    
  104.                 nextIsString = false;    
  105.             }    
  106.         }    
  107.         // 置空    
  108.         lastContents = "";    
  109.     }    
  110.         
  111.         
  112.     public void endElement(String uri, String localName, String name)    
  113.             throws SAXException {    
  114.         // 根据SST的索引值的到单元格的真正要存储的字符串    
  115.         // 这时characters()方法可能会被调用多次    
  116.         if (nextIsString) {    
  117.             try {    
  118.                 int idx = Integer.parseInt(lastContents);    
  119.                 lastContents = new XSSFRichTextString(sst.getEntryAt(idx))    
  120.                         .toString();    
  121.             } catch (Exception e) {    
  122.    
  123.             }    
  124.         }    
  125.    
  126.         // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引    
  127.         // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符    
  128.         if (name.equals("v")) {    
  129.             String value = lastContents.trim();    
  130.             value = value.equals("") ? " " : value;    
  131.             rowlist.add(curCol, value);    
  132.             curCol++;    
  133.         } else {    
  134.             // 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法    
  135.             if (name.equals("row")) {    
  136.                 optRow(sheetIndex, curRow, rowlist);    
  137.                 rowlist.clear();    
  138.                 curRow++;    
  139.                 curCol = 0;    
  140.             }    
  141.         }    
  142.     }    
  143.    
  144.     public void characters(char[] ch, int start, int length)    
  145.             throws SAXException {    
  146.         // 得到单元格内容的值    
  147.         lastContents += new String(ch, start, length);    
  148.     }    
  149.    
  150. }   
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值