java解析⼤数据量excel
1. 引包
org.apache.poi poi 3.8 org.apache.poi poi-ooxml 3.8
2. 使⽤⽅式:
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.ptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
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.del.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
l.sax.Attributes;
l.sax.InputSource;
l.sax.SAXException;
l.sax.XMLReader;
l.sax.helpers.DefaultHandler;
l.parsers.ParserConfigurationException;
l.parsers.SAXParser;
l.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
SimpleDateFormat;
import java.util.*;
/**
* 使⽤SAX模式解决XLSX⽂件,可以有效解决⽤户模式内存溢出的问题
* 该模式是POI官⽅推荐的读取⼤数据的模式,在⽤户模式下,数据量较⼤、Sheet较多、或者是有很
多⽆⽤的空⾏的情况 * ,容易出现内存溢出,⽤户模式读取Excel的典型代码如下: FileInputStream file=new
* FileInputStream("c:\\test.xlsx"); Workbook wb=new XSSFWorkbook(file);
*/
public class XLSXSaxReader {
private static final Logger logger = Logger(XLSXSaxReader.class);
enum xssfDataType {
BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER,
}
class MyXSSFSheetHandler extends DefaultHandler {
/**
* Table with styles
*/
private StylesTable stylesTable;
/**
* Table with unique strings
*/
private ReadOnlySharedStringsTable sharedStringsTable;
/**
* Destination for data
*/
private final PrintStream output;
/**
* Number of columns to read starting with leftmost
*/
private final int minColumnCount;
// Set when V start element is seen
private boolean vIsOpen;
// Set when cell start element is seen;
// used when cell close element is seen.
private xssfDataType nextDataType;
// Used to format numeric cell values.
private short formatIndex;
private String formatString;
private final DataFormatter formatter;
private int thisColumn =-1;
// The last column printed to the output stream
private int lastColumnNumber =-1;
// Gathers characters as they are seen.
private StringBuffer value;
private String[] record;
private List<String[]> rows =new ArrayList<String[]>();
private boolean isCellNull =false;
private Map<String, Object> resultMap =new HashMap<String, Object>();
private List<String> checkList =new ArrayList<String>();//校验始发城市和⽬的站点的唯⼀性/**
* Accepts objects needed while parsing.
*
* @param styles  Table of styles
* @param strings Table of shared strings
* @param cols    Minimum number of columns to show
* @param target  Sink for output
*/
public MyXSSFSheetHandler(StylesTable styles,
ReadOnlySharedStringsTable strings,int cols, PrintStream target){ this.stylesTable = styles;
this.sharedStringsTable = strings;
this.minColumnCount = cols;
this.output = target;
this.value =new StringBuffer();
this.formatter =new DataFormatter();
record =new String[this.minColumnCount];
rows.clear();// 每次读取都清空⾏集合
resultMap.clear();//清空结果集
checkList.clear();
}
/*
* (non-Javadoc)
java valueof
*
* @see
* l.sax.helpers.DefaultHandler#startElement(java.lang.String,
* java.lang.String, java.lang.String, l.sax.Attributes)
*/
public void startElement(String uri, String localName, String name,
Attributes attributes)throws SAXException {
if("inlineStr".equals(name)||"v".equals(name)){
vIsOpen =true;
// Clear contents cache
value.setLength(0);
}
// c => cell
else if("c".equals(name)){
// Get the cell reference
String r = Value("r");
int firstDigit =-1;
for(int c =0; c < r.length();++c){
if(Character.isDigit(r.charAt(c))){
firstDigit = c;
break;
}
}
thisColumn =nameToColumn(r.substring(0, firstDigit));
// Set up defaults.
this.formatIndex =-1;
this.formatString = null;
String cellType = Value("t");
String cellStyleStr = Value("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){
// It's a number, but almost certainly one
// with a special style or format
int styleIndex = Integer.parseInt(cellStyleStr);
XSSFCellStyle style = StyleAt(styleIndex);
this.formatIndex = DataFormat();
this.formatString = DataFormatString();
if(this.formatString == null)
this.formatString = BuiltinFormats
.getBuiltinFormat(this.formatIndex);
}
}
}
/*
* (non-Javadoc)
*
* @l.sax.helpers.DefaultHandler#endElement(java.lang.String,        * java.lang.String, java.lang.String)
*/
public void endElement(String uri, String localName, String name) throws SAXException {
String thisStr = null;
// v => contents of a cell
if("v".equals(name)){
// Process the value contents as required.
// Do now, as characters() may be called more than once
switch(nextDataType){
char first = value.charAt(0);
thisStr = first =='0'?"FALSE":"TRUE";
break;
case ERROR:
thisStr ="\"ERROR:"+ String()+'"';
break;
case FORMULA:
// A formula could result in a string value,
// so always add double-quote characters.
thisStr = String();
break;
case INLINESTR:
/
/ TODO: have seen an example of this, so it's untested.
XSSFRichTextString rtsi =new XSSFRichTextString(
thisStr = String();
break;
case SSTINDEX:
String sstIndex = String();
try{
int idx = Integer.parseInt(sstIndex);
XSSFRichTextString rtss =new XSSFRichTextString(
thisStr = String();
}catch(NumberFormatException ex){
output.println("Failed to parse SST index '"+ sstIndex
+"': "+ ex.toString());
}
break;
case NUMBER:
String n = String();
// 判断是否是⽇期格式
if(HSSFDateUtil.isADateFormat(this.formatIndex, n)){
Double d = Double.parseDouble(n);
Date date = JavaDate(d);
thisStr =formateDateToString(date);
}else if(this.formatString != null)
thisStr = formatter.formatRawCellContents(
Double.parseDouble(n),this.formatIndex,
this.formatString);
else
thisStr = n;
break;
default:
thisStr ="(TODO: Unexpected type: "+ nextDataType +")";
break;
}
// Output after we've seen the string contents
// Emit commas for any fields that were missing on this row
if(lastColumnNumber ==-1){
lastColumnNumber =0;
}
//判断单元格的值是否为空
if(thisStr == null ||"".equals(isCellNull)){
isCellNull =true;// 设置单元格是否为空值
}
record[thisColumn]= thisStr;
if(thisColumn >-1)
lastColumnNumber = thisColumn;
}else if("row".equals(name)){//⼀⾏结尾.校验数据有效性病并缓存数据
// Print out any missing commas if needed
if(minColumns >0){
// Columns are 0 based
if(lastColumnNumber ==-1){
lastColumnNumber =0;
}
if(isCellNull ==false&& StringUtils.isNotEmpty(record[0])&& StringUtils.isNotEmpty(record[2]))// 判断前两个单元格是否为空值,为空值则不添加此⾏
{
//校验某⼏列的组合的唯⼀性
if(rows.size()>0){
String uniqueId = String.valueOf(record[0])+"-"+ String.valueOf(record[2]);
ains(uniqueId)){
<("请检查第"+ rows.size()+"⾏指定列是唯⼀的");
resultMap.put("error","请检查第"+ rows.size()+"⾏是唯⼀的");
throw new SAXException();
}else{
checkList.add(uniqueId);
}
}
rows.add(record.clone());
isCellNull =false;
for(int i =0; i < record.length; i++){
record[i]= null;
}
}else{
logger.info("第"+ rows.size()+"⾏ID为空,请检查后再上传");
resultMap.put("error","第"+ rows.size()+"⾏ID为空,请检查后再上传");
throw new SAXException();
}
}
lastColumnNumber =-1;
}
}
public List<String[]>getRows(){
return rows;
}
public void setRows(List<String[]> rows){
}
/**
* Captures characters only if a suitable element is open. Originally
* was just "v"; extended for inlineStr also.
*/
public void characters(char[] ch,int start,int length)
throws SAXException {
if(vIsOpen)
value.append(ch, start, length);
}
/**
* Converts an Excel column name like "C" to a zero-based index.
*
* @param name
* @return Index corresponding to the specified name
*/

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。