- 浏览: 290396 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (163)
- ETL (4)
- Oracle (24)
- Win (2)
- Apache (5)
- struts2 (1)
- ArcGIS (21)
- Java (17)
- other (6)
- JavaScript (4)
- Xml (4)
- c# (2)
- webSphere (5)
- Ext (2)
- Flex (35)
- Svn (3)
- tomcat (3)
- MyEclipse (4)
- MySQL (2)
- ibatis (2)
- log4j (4)
- spring (1)
- SqlServer (2)
- android (4)
- ios (3)
- SDE (2)
- mac (1)
- Linux (9)
- Mina2 (1)
最新评论
-
markss:
您好,请问kettle循环处理的内存泄漏问题是否已经解决了?毕 ...
Kettle -
1qqqqqq:
图呢 ???
Myeclipse 9.0集成FLASH BUILDER 4.5 -
hanyi366:
现在MyEclipse 都2014版了,好像MyEclipse ...
Visual Editor 插件 安装 -
cnjmwr:
MyEclipse8.6的Eclipse版本是3.5的 ve1 ...
Visual Editor 插件 安装 -
cloudphoenix:
大神 我特地登陆来回帖,真是帮了我的大忙了。看了一个多月的AS ...
FlexGlobals.topLevelApplication
前段时间,需要进行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{}的性能消耗相当大。还有做批量处理的时候一定要控制操作次数。
发表评论
-
Java中byte与16进制字符串的互相转换
2014-09-07 07:43 743Java中byte用二进制表示占用8位,而我们知道16进制 ... -
SynchronizedMap和ConcurrentHashMap的深入分析
2014-06-19 10:33 623在开始之前,先介绍下Map是什么? javadoc中对M ... -
多线程下使用 SimpleDateFormat 的问题
2014-03-18 12:38 771最近用到多线程写通信服务,发现在解析时间是一直莫名的错误, ... -
java内存限制
2012-07-12 20:38 930回顾一下java内存限制的几个参数的具体含义 -Xm ... -
UTC GMT CST时间
2012-07-05 15:59 2533GMT(Greenwich Mean Time,格林威治 ... -
FLEX权限--使用RemoteObject交互结合spring AOP控制项目权限教程
2012-03-04 16:55 847FLEX使用remoteobject交互结合sprin ... -
iBatis中的insert如何返回个类数据库的主键
2012-02-24 11:03 991<SPAN style="COLOR: #ff ... -
java.util.ConcurrentModificationException异常
2012-01-14 12:59 9611、 今天在写一个带缓 ... -
JAVA中ArrayList 与 Vector 的线程安全问题
2012-01-13 18:45 3651JAVA中ArrayList是否允许两个线程同时进行插入和删除 ... -
java calendar
2011-12-22 16:27 1735import java.text.DateFormat; ... -
Servlet中init-param and content-param
2011-11-08 08:56 826Servlet中init-param and content- ... -
HttpRequestProxy 请求代理 post方法
2011-10-28 15:31 4308* * * * Title: Ht ... -
HttpRequestProxy 请求代理 post方法
2011-10-28 15:30 1373写道 * * * * Title: HttpR ... -
XmlHttpProxy
2011-08-23 08:41 1013XmlHttpProxy /* Copyright ... -
super.init(config)
2011-08-22 11:45 3009servlet的init(ServletConfig conf ... -
URL工具类
2011-08-18 14:45 1006package ssh.util; import ...
相关推荐
Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word的所有资料Java 操作Excel和Word...
当我们谈论“Java操作Excel表格”时,通常是指使用Java来读取、写入或处理Microsoft Excel文件,这在数据分析、报表生成或者数据交换等场景中非常常见。本主题将围绕Java如何与Excel交互进行深入探讨。 首先,Java...
java操作Excel java操作Excel java操作Excel
### Java操作Excel详解 #### 一、Java Excel API简介 Java Excel API是一个强大的开源库,允许开发者使用Java语言轻松地创建、更新以及读取Excel文件。这个库支持多种Excel文件格式,包括较旧版本(如.xls)和较新...
### 利用JAVA操作EXCEL文件的关键知识点 #### 一、JAVA EXCEL API 简介 - **项目背景**:随着Web应用的发展,越来越多的应用场景需要通过Web端操作Excel文件,而传统的CSV文件虽然可以被Excel打开,但无法实现对...
### Java操作Excel表格经典案例分析 #### 一、引言 在日常办公环境中,Microsoft Office套件中的Excel因其强大的数据处理能力而被广泛使用。在Java编程领域,开发者经常需要处理Excel文件,如批量导入导出数据、...
java操作excel读写,可以根据自己的需要灵活修改。导入导出excel
java是不能提供java调用excel里的函数的,所以我提供这个例子,让大家参考,必须导入jxl.jar包哦!
java操作excel实现水印图片
Java操作excel工具
Java操作Excel是软件开发中常见的任务,特别是在数据分析、报表生成或数据导入导出场景下。在Java中,我们可以借助特定的库来实现这些功能,其中一个广泛使用的库就是Apache POI项目。Apache POI是一个开源的Java ...
Java操作Excel的开源库在开发过程中常常被广泛使用,特别是在数据处理、报表生成以及与用户交互的场景下。JExcelAPI是一个这样的库,它允许Java开发者方便地读取、写入以及修改Microsoft Excel文件,无需依赖Excel...
Java操作Excel是常见的数据处理需求,特别是在数据分析、报表生成或者数据导入导出等场景中。在Java中,我们可以借助Apache POI库来实现对Excel文件的读写操作。Apache POI是一个开源项目,提供了API来处理Microsoft...
### Java操作Excel教程详解 #### 一、POI简介与背景 **Jakarta POI** 是Apache的一个子项目,它的主要目标是处理OLE2对象。POI提供了一组用于操作Microsoft Office文件(如Word和Excel)的Java API。其中,**HSSF*...
在Java编程中,Apache POI库是一个非常流行的用于读写Microsoft Office格式文件的库,包括Excel。...通过熟练掌握这些知识点,开发者可以高效地在Java程序中生成和操作Excel文件,满足各种业务需求。
"Java生成Excel图表" Java生成Excel图表是使用Java语言来生成Excel图表的过程。Excel图表是指使用Excel软件生成的图表,例如柱状图、折线图、饼状图等。Java语言可以使用各种库和框架来生成Excel图表,例如...
Java 操作 Excel 表格是一项常见的任务,尤其在数据处理和报告生成方面。在这个场景中,我们使用了一个名为 JExcelApi(简称 JXL)的 Java 库来实现这个功能。JXL 是一个开源的 Java 库,允许程序员读取、写入和修改...
在Java编程环境中,操作Excel是一项常见的任务,尤其在数据处理、报表生成或数据分析等领域。Excel文件格式主要有.xls(老版本)和.xlsx(新版本),两者都可以通过Java进行读写操作。以下将详细介绍如何使用Java来...
java操作Excel的多表、多列、多行完整代码(无需修改)