文档章节

java读写有大量数据的excel的方法

开源中国首席----
 开源中国首席----
发布于 2014/05/23 14:44
字数 1065
阅读 122
收藏 2

场景:

 需要读取超过5万行的数据,然后经过业务处理后,再写入到excel中。

问题描述:

当数据量大的时候,在读和写如果采用普通的poi给予的方法都会报heap OutOfMemoryError的问题。

解决方案:

1、读数据解决方案
import java.io.InputStream;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import org.apache.poi.xssf.eventusermodel.XSSFReader;

import org.apache.poi.xssf.model.SharedStringsTable;

import org.apache.poi.xssf.usermodel.XSSFRichTextString;

import org.apache.poi.openxml4j.opc.OPCPackage;

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;

/**

* XSSF and SAX (Event API)

*/

public abstract class XxlsAbstract extends DefaultHandler {  

private SharedStringsTable sst;  

private String lastContents;  

private boolean nextIsString;  


private int sheetIndex = -1;  

private List<String> rowlist = new ArrayList<String>();  

private int curRow = 0;     //当前行  

private int curCol = 0;     //当前列索引  

private int preCol = 0;     //上一列列索引  

private int titleRow = 0;   //标题行,一般情况下为0  

private int rowsize = 0;    //列数  

private String flag ="";//保存报表类型

private List<Map<String,String>>listReportMap = null;

//excel记录行操作方法,以行索引和行元素列表为参数,对一行元素进行操作,元素为String类型  

//  public abstract void optRows(int curRow, List<String> rowlist) throws SQLException ;  


//excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型  

public abstract void optRows(int sheetIndex,int curRow, List<String> rowlist,String flag,List<Map<String,String>>listReportMap) throws SQLException;  


//只遍历一个sheet,其中sheetId为要遍历的sheet索引,从1开始,1-3  

public void processOneSheet(String filename,int sheetId,String flag,List<Map<String,String>> listReportMap) throws Exception {

this.listReportMap = listReportMap;

this.flag = flag;

OPCPackage pkg = OPCPackage.open(filename);  

XSSFReader r = new XSSFReader(pkg);  

SharedStringsTable sst = r.getSharedStringsTable();  


XMLReader parser = fetchSheetParser(sst);  


// rId2 found by processing the Workbook  

// 根据 rId# 或 rSheet# 查找sheet  

InputStream sheet2 = r.getSheet("rId"+sheetId);  

sheetIndex++;  

InputSource sheetSource = new InputSource(sheet2);  

parser.parse(sheetSource);  

sheet2.close();  

}  


/** 

* 遍历 excel 文件 

*/

public void process(String filename) throws Exception {  

OPCPackage pkg = OPCPackage.open(filename);  

XSSFReader r = new XSSFReader(pkg);  

SharedStringsTable sst = r.getSharedStringsTable();  


XMLReader parser = fetchSheetParser(sst);  


Iterator<InputStream> sheets = r.getSheetsData();  

while (sheets.hasNext()) {  

curRow = 0;  

sheetIndex++;  

InputStream sheet = sheets.next();  

InputSource sheetSource = new InputSource(sheet);  

parser.parse(sheetSource);  

sheet.close();  

}  

}  


public XMLReader fetchSheetParser(SharedStringsTable sst)  

throws SAXException {  

XMLReader parser = XMLReaderFactory  

.createXMLReader("org.apache.xerces.parsers.SAXParser");  

this.sst = sst;  

parser.setContentHandler(this);  

return parser;  

}  


public void startElement(String uri, String localName, String name,  

Attributes attributes) throws SAXException {  

// c => 单元格  

if (name.equals("c")) {  

// 如果下一个元素是 SST 的索引,则将nextIsString标记为true  

String cellType = attributes.getValue("t");  

String rowStr = attributes.getValue("r");  

curCol = this.getRowIndex(rowStr);  

if (cellType != null && cellType.equals("s")) {  

nextIsString = true;  

} else {  

nextIsString = false;  

}  

}  

// 置空  

lastContents = "";  

}  


public void endElement(String uri, String localName, String name)  

throws SAXException {  

// 根据SST的索引值的到单元格的真正要存储的字符串  

// 这时characters()方法可能会被调用多次  

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")) {  

String value = lastContents.trim();  

value = value.equals("")?" ":value;  

int cols = curCol-preCol;  

if (cols>1){  

for (int i = 0;i < cols-1;i++){  

rowlist.add(preCol,"");  

}  

}  

preCol = curCol;  

rowlist.add(curCol-1, value);  

}else {  

//如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法  

if (name.equals("row")) {  

int tmpCols = rowlist.size();  

if(curRow>this.titleRow && tmpCols<this.rowsize){  

for (int i = 0;i < this.rowsize-tmpCols;i++){  

rowlist.add(rowlist.size(), "");  

}  

}  

try { <span style="color:#ff0000;"> optRows(sheetIndex,curRow,rowlist,this.flag,this.listReportMap);</span> } catch (SQLException e) {  

e.printStackTrace();  

}  

if(curRow==this.titleRow){  

this.rowsize = rowlist.size();  

}  

rowlist.clear();  

curRow++;  

curCol = 0;  

preCol = 0;  

}  

}  

}  


public void characters(char[] ch, int start, int length)  

throws SAXException {  

//得到单元格内容的值  

lastContents += new String(ch, start, length);  

}  


//得到列索引,每一列c元素的r属性构成为字母加数字的形式,字母组合为列索引,数字组合为行索引,  

//如AB45,表示为第(A-A+1)*26+(B-A+1)*26列,45行  

public int getRowIndex(String rowStr){  

rowStr = rowStr.replaceAll("[^A-Z]", "");  

byte[] rowAbc = rowStr.getBytes();  

int len = rowAbc.length;  

float num = 0;  

for (int i=0;i<len;i++){  

num += (rowAbc[i]-'A'+1)*Math.pow(26,len-i-1 );  

}  

return (int) num;  

}  


public int getTitleRow() {  

return titleRow;  

}  


public void setTitleRow(int titleRow) {  

this.titleRow = titleRow;  

}  

}

使用方法

 这个方法是在读2007版本的时候,可以自己写一个类然后继承这个抽象类。重写optRows。

在146行可以看到,这个抽象类,会调用子类你重写的方法,所以再子类中的方法可以直接拿到该数据。这种读的方式速度很快,5w行数据也就6,7秒就可以搞定

2、写大量数据解决方案

可以将写出的数据批量写出,1w行数据一个sheet,或者分批写不同的excel。就我测试的数据来看。分批写不同的excel速度会比较快。

注:以上的读取代码来自于网络

© 著作权归作者所有

开源中国首席----
粉丝 6
博文 44
码字总数 38812
作品 0
西安
私信 提问
Java程序员从笨鸟到菜鸟之(一百零四)java操作office和pdf文件(二)利用POI实现数据导出excel报表

在上一篇博客中,我们简单介绍了java读取word,excel和pdf文档内容 ,但在实际开发中,我们用到最多的是把数据库中数据导出excel报表形式。不仅仅简单的读取office中的数据.尤其是在生产管理...

长平狐
2012/11/12
1K
0
Aspose.Cells for Reporting Services 2.0.0 发布

Aspose.Cells for Reporting Services 2.0.0 发布,此版本更新内容如下: 此版本优化了 Aspose.Cells for Reporting Services 报表设计工具; 允许用户下载 Aspose.Cells 对 Excel x64 的插件...

oschina
2014/04/05
336
0
Java读取Excel数据:基于Apache POI(一)

版权声明:本文为Zhang Phil原创文章,请不要转载! https://blog.csdn.net/zhangphil/article/details/85302347 Java读取Excel数据:基于Apache POI(一) Java本身不支持直接读取微软的Exc...

zhangphil
2018/12/27
0
0
Apache POI操作Excel导出JAVABEAN对象方法

Apache POI操作Excel导出方法说明 Apache的POI组件是Java操作Microsoft Office办公套件的强大API,其中对Word,Excel和PowperPoint都有支持,当然使用较多的还是Excel,因为Word和PowerPoin...

JAVA枪手
2014/05/08
650
0
使用 Apache 的 POI 和 HSSF 将 Excel 电子表格数据加载到 DB2

简介 在 developerWorks DB2 上本文的 先行篇 中,我们研究了 Apache 的 POI 项目的开放源代码产品。期间,我们开始在了解 SQL 的技术专家和通常将电子表格选作工具的商务专家之间架起一座桥...

红薯
2008/12/05
948
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
昨天
7
0
用最通俗的方法讲spring [一] ──── AOP

@[TOC](用最通俗的方法讲spring [一] ──── AOP) 写这个系列的目的(可以跳过不看) 自己写这个系列的目的,是因为自己是个比较笨的人,我曾一度怀疑自己的智商不适合干编程这个行业.因为在我...

小贼贼子
昨天
7
0
Flutter系列之在 macOS 上安装和配置 Flutter 开发环境

本文为Flutter开发环境在macOS下安装全过程: 一、系统配置要求 想要安装并运行 Flutter,你的开发环境需要最低满足以下要求: 操作系统:macOS(64位) 磁盘空间:700 MB(不包含 IDE 或其余...

過愙
昨天
6
0
OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
昨天
2.6K
16
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
昨天
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部