`
hanyi366
  • 浏览: 290396 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java 操作 excel 2010

    博客分类:
  • Java
 
阅读更多

 前段时间,需要进行excel2010数据的解析。先是找组件,jxl不支持,然后时poi。poi倒是可以解析excel10(XSSF),但是数据量一大就会内存溢出(但是用的还是一个小破笔记本1000+行就会内存溢出)。这下傻眼了,没办法,只好到网上找资料了,发现没什么能用,最后在apache 官网上找到一个示例 XLSX2CSV(地址:http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java),对它进行了改写。

excel 从07开始其数据存储结构就发生了改变,现在是用多个xml进行存储的,可以直接用解压软件进行打开,就可以看到里面的组成(可以参考:http://blog.csdn.net/lupengcheng2025/article/details/5339998)。

好了,现在开始解析。

 



import java.io.IOException;
import java.io.InputStream;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.DataFormatter;
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.XSSFCellStyle;
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;



/**
* 读取excel xlsx(07、10)
* @author dallas16
*
*/
public class ExcelAnalysisXLSX extends DefaultHandler {
/**
* excel样式
*/
private StylesTable stylesTable;
/**
* 好像
*/
private ReadOnlySharedStringsTable sharedStringsTable;
/**
* 单元格中的数据可能的数据类型
*
*/
enum xssfDataType {
BOOL,
ERROR,
FORMULA,
INLINESTR,
SSTINDEX,
NUMBER,
}
/**
* 存储某个cell的类型
*/
private xssfDataType nextDataType = xssfDataType.NUMBER;
/**
* 某个cell的值
*/
private String value = "";

private short formatIndex;
private String formatString;
private final DataFormatter formatter = new DataFormatter();

/**
* 存储某一行的数据
*/
private List<String> rowlist = new ArrayList<String>();
/**
* excel的sheet名称
*/
private String sheetName;
/**
* excel 的路径
*/
private String path;
/**
* 准备存放读取结果
*/
private List<List<String>> datas = new ArrayList<List<String>>();
/**
* 当前的数据时第几列
*/
private int thisColumn;
private int lastColumnNumber;

/**
* 匹配开头和结尾是否是数字
*/
private static Pattern p1 = Pattern.compile("^\\d.*\\d$");



/**
* 对单元格的数据进行处理,重写了DefaultHandler中characters方法(其实DefaultHandler中的所有方法都没有方法体),
* 这个方法在读取过程中会被自动调用
* @param ch
* @param start
* @param length
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
value = value+new String(ch,start,length);
}

/**
* 在读取元素结束时的 处理,主要是判断是不是一个单元格结束,是不是一行结束,是的话进行相应的处理
* 是单元格则将数据(value)添加到rowlist的相应位置
* 是一行结束的话则将 rowlist添加到sheetVo中
* @param uri
* @param localName
* @param qName
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if ("v".equals(qName)) {
endDeal();
} else if ("row".equals(qName)) {
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
this.dealData();
lastColumnNumber = -1;
}

}

/**
* 在读取元素开始时的 处理,
* @param uri
* @param localName
* @param qName
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if ("inlineStr".equals(qName) || "v".equals(qName)) {
value = "";
}
else if ("c".equals(qName)) {
String r = attributes.getValue("r");
int firstDigit = -1;
int length = r.length();
for (int c = 0; c < length; ++c) {
if (Character.isDigit(r.charAt(c))) {
firstDigit = c;
break;
}
}
thisColumn = nameToColumn(r.substring(0, firstDigit));
dealDataType(attributes);
}

}

/**
* 对指定的sheet进行处理
* @param styles
* @param strings
* @param sheetInputStream
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public void processSheet(
StylesTable styles,
ReadOnlySharedStringsTable strings,
InputStream sheetInputStream)
throws IOException, ParserConfigurationException, SAXException {

InputSource sheetSource = new InputSource(sheetInputStream);
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxFactory.newSAXParser();
XMLReader sheetParser = saxParser.getXMLReader();
this.stylesTable = styles ;
this.sharedStringsTable = strings;
sheetParser.setContentHandler(this);
sheetParser.parse(sheetSource);
}

/**
*
* @param excelUtilBean.getPath() 需要读取的excel的路径
* @param excelUtilBean.getSheetName() 如果值不为空则按名称进行解析
* @param excelUtilBean.getSheetNumber() 如果值为空则按指定的顺序进行解析
* @throws IOException
* @throws OpenXML4JException
* @throws ParserConfigurationException
* @throws SAXException
*/
@SuppressWarnings("unused")
public void process()
throws IOException, OpenXML4JException, ParserConfigurationException, SAXException {
OPCPackage pkg = OPCPackage.open(path);
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(pkg);
XSSFReader xssfReader = new XSSFReader(pkg);
StylesTable styles = xssfReader.getStylesTable();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
int index = 0;
boolean flag = false;
while (iter.hasNext()) { // 做判断,看是否是自己需要解析的那一个sheet
InputStream stream = iter.next();
String sheetName = iter.getSheetName();
if(iter.getSheetName().equals(sheetName)){
processSheet(styles, strings, stream);
flag = true;
break;
}
stream.close();
++index;
}
if(!flag ){
String errorInfo = "名为 ‘"+sheetName+"’ 的sheet不存在!";
throw new RuntimeException(errorInfo);
}
pkg = null;
strings = null;
xssfReader = null;
styles = null;
}

/**
* 结束元素时的处理,根据情况将数据添加到 rowlist中
*/
public void endDeal(){
String thisStr = null;
thisStr = dealData(value,thisStr); //对单元格的数据进行类型处理
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
for (int i = lastColumnNumber+1; i < thisColumn; ++i){
rowlist.add(" ");
}
rowlist.add(thisStr==null?"":thisStr);
if (thisColumn > -1){
lastColumnNumber = thisColumn;
}
}

/**
* 将数据添加到sheetVo中去,也是根据条件进行不同的处理
*/
public void dealData(){
if(rowlist != null && rowlist.size() != 0 ){
datas.add(rowlist);
rowlist = null;

}
if(rowlist == null){
rowlist = new ArrayList<String>();
}
}

/**
* 好像是计算当前是第几列
* @param name
* @return
*/
private int nameToColumn(String name) {
int column = -1;
int length = name.length();
for (int i = 0; i < length ; ++i) {
int c = name.charAt(i);
column = (column + 1) * 26 + c - 'A';
}
return column;
}

/**
* 对解析出来的数据进行类型处理
* @param value 单元格的值(这时候是一串数字)
* @param thisStr 一个空字符串
* @return
*/
@SuppressWarnings("deprecation")
public String dealData(String value,String thisStr){
switch (nextDataType) {//这几个的顺序不能随便交换,交换了很可能会导致数据错误
case BOOL:
char first = value.charAt(0);
thisStr = first == '0' ? "FALSE" : "TRUE";
break;
case ERROR:
thisStr = "\"ERROR:" + value.toString() + '"';
break;
case FORMULA:
thisStr = '"' + value.toString() + '"';
break;
case INLINESTR:
XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());

thisStr = rtsi.toString() ;
rtsi = null;
break;
case SSTINDEX:
String sstIndex = value.toString();
try {
int idx = Integer.parseInt(sstIndex);
XSSFRichTextString rtss = new XSSFRichTextString(sharedStringsTable.getEntryAt(idx));
thisStr = rtss.toString();
rtss = null;
}
catch (NumberFormatException ex) {
thisStr = value.toString();
}
break;
case NUMBER:
String n = value.toString();
if (this.formatString != null)
thisStr = formatter.formatRawCellContents(Double.parseDouble(n), this.formatIndex, this.formatString);
else
thisStr = n;
break;
default:
thisStr = " ";

break;
}

try {
Date date = new Date(thisStr);

} catch (Exception e) {

}

return thisStr;
}


/**
* 处理数据类型
* @param attributes
*/
public void dealDataType(Attributes attributes){
this.nextDataType = xssfDataType.NUMBER;
this.formatIndex = -1;
this.formatString = null;
String cellType = attributes.getValue("t");
String cellStyleStr = attributes.getValue("s");

if ("b".equals(cellType))
nextDataType = xssfDataType.BOOL;
else if ("e".equals(cellType))
nextDataType = xssfDataType.ERROR;
else if ("inlineStr".equals(cellType))
nextDataType = xssfDataType.INLINESTR;
else if ("s".equals(cellType))
nextDataType = xssfDataType.SSTINDEX;
else if ("str".equals(cellType))
nextDataType = xssfDataType.FORMULA;
else if (cellStyleStr != null) {
int styleIndex = Integer.parseInt(cellStyleStr);
XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
this.formatIndex = style.getDataFormat();
this.formatString = style.getDataFormatString();
if (this.formatString == null)
this.formatString = BuiltinFormats.getBuiltinFormat(this.formatIndex);
}
}
/**
* 将数据添加到rowlist中
* @param str 单元格的数据
* @param num 列号
*/
public void addRowlist(String str , int num){

if(rowlist.size() >= num){
rowlist.add(num, str==null?"":str);
} else {
int size = rowlist.size();
int newNum = num+1;
for(int i = size; i < newNum; i++){
rowlist.add("");
}
rowlist.add(num, str==null?"":str);
}
}

public String getSheetName() {
return sheetName;
}

public void setSheetName(String sheetName) {
this.sheetName = sheetName;
}

public String getPath() {
return path;
}

public void setPath(String path) {
this.path = path;
}

public List<List<String>> getDatas() {
return datas;
}

public void setDatas(List<List<String>> datas) {
this.datas = datas;
}

public static void main(String[] args) throws Exception {

ExcelAnalysisXLSX excel = new ExcelAnalysisXLSX();
excel.setPath("F:/b.xlsx");
excel.setSheetName("Sheet1");
excel.process();
List<List<String>> datas = excel.getDatas();
for(List<String> data : datas){
System.out.println(data);
}
}

}


其中需要的jar包:poi相关jar、xmlBean-2.3.0.jar、dom4j.jar。

这样就可以解析了,我测试过的最大的是13000条数据(我系统中的解析10w条数据时没有问题的,但是做了批量处理),更大的数据就需要做批量处理了,因为数据就算能解析出来,但是list中已经装不下这么多了(当然这和电脑配置有关系的)。然后还需要考虑解析的性能问题,其中的日期类型处理那里的try{}catch{}的性能消耗相当大。还有做批量处理的时候一定要控制操作次数。

分享到:
评论
2 楼 fangtinghua 2012-11-16  
空格问题怎么处理?
1 楼 qiyang199132 2012-03-23  
不错 呵呵。

相关推荐

    Java 操作Excel和Word的所有资料

    Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word...

    Java操作Excel表格

    当我们谈论“Java操作Excel表格”时,通常是指使用Java来读取、写入或处理Microsoft Excel文件,这在数据分析、报表生成或者数据交换等场景中非常常见。本主题将围绕Java如何与Excel交互进行深入探讨。 首先,Java...

    jxl Java操作Excel

    java操作Excel java操作Excel java操作Excel

    Java操作Excel详解

    ### Java操作Excel详解 #### 一、Java Excel API简介 Java Excel API是一个强大的开源库,允许开发者使用Java语言轻松地创建、更新以及读取Excel文件。这个库支持多种Excel文件格式,包括较旧版本(如.xls)和较新...

    利用JAVA操作EXCEL文件.pdf

    ### 利用JAVA操作EXCEL文件的关键知识点 #### 一、JAVA EXCEL API 简介 - **项目背景**:随着Web应用的发展,越来越多的应用场景需要通过Web端操作Excel文件,而传统的CSV文件虽然可以被Excel打开,但无法实现对...

    java 操作excel表格经典例子

    ### Java操作Excel表格经典案例分析 #### 一、引言 在日常办公环境中,Microsoft Office套件中的Excel因其强大的数据处理能力而被广泛使用。在Java编程领域,开发者经常需要处理Excel文件,如批量导入导出数据、...

    java操作excel读写

    java操作excel读写,可以根据自己的需要灵活修改。导入导出excel

    java操作excel,函数计算

    java是不能提供java调用excel里的函数的,所以我提供这个例子,让大家参考,必须导入jxl.jar包哦!

    java操作excel实现水印图片

    java操作excel实现水印图片

    Java操作excel工具

    Java操作excel工具

    java操作excel的jar包

    Java操作Excel是软件开发中常见的任务,特别是在数据分析、报表生成或数据导入导出场景下。在Java中,我们可以借助特定的库来实现这些功能,其中一个广泛使用的库就是Apache POI项目。Apache POI是一个开源的Java ...

    Java操作Excel的开源库

    Java操作Excel的开源库在开发过程中常常被广泛使用,特别是在数据处理、报表生成以及与用户交互的场景下。JExcelAPI是一个这样的库,它允许Java开发者方便地读取、写入以及修改Microsoft Excel文件,无需依赖Excel...

    java操作excel

    Java操作Excel是常见的数据处理需求,特别是在数据分析、报表生成或者数据导入导出等场景中。在Java中,我们可以借助Apache POI库来实现对Excel文件的读写操作。Apache POI是一个开源项目,提供了API来处理Microsoft...

    最全最实用的Java操作Excel教程

    ### Java操作Excel教程详解 #### 一、POI简介与背景 **Jakarta POI** 是Apache的一个子项目,它的主要目标是处理OLE2对象。POI提供了一组用于操作Microsoft Office文件(如Word和Excel)的Java API。其中,**HSSF*...

    java操作excel实例

    在Java编程中,Apache POI库是一个非常流行的用于读写Microsoft Office格式文件的库,包括Excel。...通过熟练掌握这些知识点,开发者可以高效地在Java程序中生成和操作Excel文件,满足各种业务需求。

    java生成excel图表

    "Java生成Excel图表" Java生成Excel图表是使用Java语言来生成Excel图表的过程。Excel图表是指使用Excel软件生成的图表,例如柱状图、折线图、饼状图等。Java语言可以使用各种库和框架来生成Excel图表,例如...

    通过java操作excel表格的工具类库

    Java 操作 Excel 表格是一项常见的任务,尤其在数据处理和报告生成方面。在这个场景中,我们使用了一个名为 JExcelApi(简称 JXL)的 Java 库来实现这个功能。JXL 是一个开源的 Java 库,允许程序员读取、写入和修改...

    java操作excel的实例

    在Java编程环境中,操作Excel是一项常见的任务,尤其在数据处理、报表生成或数据分析等领域。Excel文件格式主要有.xls(老版本)和.xlsx(新版本),两者都可以通过Java进行读写操作。以下将详细介绍如何使用Java来...

    java操作Excel完整代码

    java操作Excel的多表、多列、多行完整代码(无需修改)

Global site tag (gtag.js) - Google Analytics