Browse Source

优化读写逻辑

pull/507/head
zhuangjiaju 5 years ago
parent
commit
c8a14f3da4
  1. 31
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
  2. 61
      src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java
  3. 42
      src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
  4. 10
      src/main/java/com/alibaba/excel/metadata/CellData.java
  5. 2
      src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java
  6. 11
      src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java
  7. 11
      src/main/java/com/alibaba/excel/util/FileUtils.java
  8. 12
      src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java
  9. 53
      src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java

31
src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java

@ -35,25 +35,20 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
} }
} }
private void choiceExcelExecutor() { private void choiceExcelExecutor() throws Exception {
try { ExcelTypeEnum excelType = analysisContext.readWorkbookHolder().getExcelType();
ExcelTypeEnum excelType = analysisContext.readWorkbookHolder().getExcelType(); if (excelType == null) {
if (excelType == null) { excelExecutor = new XlsxSaxAnalyser(analysisContext);
return;
}
switch (excelType) {
case XLS:
excelExecutor = new XlsSaxAnalyser(analysisContext);
break;
case XLSX:
excelExecutor = new XlsxSaxAnalyser(analysisContext); excelExecutor = new XlsxSaxAnalyser(analysisContext);
return; break;
} default:
switch (excelType) {
case XLS:
excelExecutor = new XlsSaxAnalyser(analysisContext);
break;
case XLSX:
excelExecutor = new XlsxSaxAnalyser(analysisContext);
break;
default:
}
} catch (Exception e) {
throw new ExcelAnalysisException("File type error,io must be available markSupported,you can do like "
+ "this <code> new BufferedInputStream(new FileInputStream(\\\"/xxxx\\\"))</code> \"", e);
} }
} }

61
src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java

@ -1,12 +1,17 @@
package com.alibaba.excel.analysis.v03.handlers; package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.record.StringRecord;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
/** /**
@ -15,9 +20,13 @@ import com.alibaba.excel.metadata.CellData;
* @author Dan Zheng * @author Dan Zheng
*/ */
public class FormulaRecordHandler extends AbstractXlsRecordHandler { public class FormulaRecordHandler extends AbstractXlsRecordHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(FormulaRecordHandler.class);
private static final String ERROR = "#VALUE!";
private int nextRow; private int nextRow;
private int nextColumn; private int nextColumn;
private boolean outputNextStringRecord; private boolean outputNextStringRecord;
private CellData tempCellData;
private FormatTrackingHSSFListener formatListener; private FormatTrackingHSSFListener formatListener;
private HSSFWorkbook stubWorkbook; private HSSFWorkbook stubWorkbook;
@ -38,24 +47,56 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler {
this.row = frec.getRow(); this.row = frec.getRow();
this.column = frec.getColumn(); this.column = frec.getColumn();
CellType cellType = CellType.forInt(frec.getCachedResultType());
if (Double.isNaN(frec.getValue())) { String formulaValue = null;
// Formula result is a string try {
// This is stored in the next record formulaValue = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
outputNextStringRecord = true; } catch (Exception e) {
nextRow = frec.getRow(); LOGGER.warn("Get formula value error.{}", e.getMessage());
nextColumn = frec.getColumn(); }
} else { switch (cellType) {
this.cellData = new CellData(frec.getValue()); case STRING:
// Formula result is a string
// This is stored in the next record
outputNextStringRecord = true;
nextRow = frec.getRow();
nextColumn = frec.getColumn();
tempCellData = new CellData(CellDataTypeEnum.STRING);
tempCellData.setFormula(Boolean.TRUE);
tempCellData.setFormulaValue(formulaValue);
break;
case NUMERIC:
this.cellData = new CellData(frec.getValue());
this.cellData.setFormula(Boolean.TRUE);
this.cellData.setFormulaValue(formulaValue);
break;
case ERROR:
this.cellData = new CellData(CellDataTypeEnum.ERROR);
this.cellData.setStringValue(ERROR);
this.cellData.setFormula(Boolean.TRUE);
this.cellData.setFormulaValue(formulaValue);
break;
case BOOLEAN:
this.cellData = new CellData(frec.getCachedBooleanValue());
this.cellData.setFormula(Boolean.TRUE);
this.cellData.setFormulaValue(formulaValue);
break;
default:
this.cellData = new CellData(CellDataTypeEnum.EMPTY);
this.cellData.setFormula(Boolean.TRUE);
this.cellData.setFormulaValue(formulaValue);
break;
} }
} else if (record.getSid() == StringRecord.sid) { } else if (record.getSid() == StringRecord.sid) {
if (outputNextStringRecord) { if (outputNextStringRecord) {
// String for formula // String for formula
StringRecord srec = (StringRecord)record; StringRecord srec = (StringRecord)record;
this.cellData = new CellData(srec.getString()); this.cellData = tempCellData;
this.cellData.setStringValue(srec.getString());
this.row = nextRow; this.row = nextRow;
this.column = nextColumn; this.column = nextColumn;
outputNextStringRecord = false; outputNextStringRecord = false;
tempCellData = null;
} }
} }
} }

42
src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java

@ -13,17 +13,21 @@ import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.SAXParserFactory;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.usermodel.XSSFRelation; import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument; import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.XMLReader; import org.xml.sax.XMLReader;
import com.alibaba.excel.analysis.ExcelExecutor; import com.alibaba.excel.analysis.ExcelExecutor;
import com.alibaba.excel.cache.Ehcache; import com.alibaba.excel.cache.Ehcache;
import com.alibaba.excel.cache.MapCache;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadSheet;
@ -35,6 +39,11 @@ import com.alibaba.excel.util.FileUtils;
* @author jipengfei * @author jipengfei
*/ */
public class XlsxSaxAnalyser implements ExcelExecutor { public class XlsxSaxAnalyser implements ExcelExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(XlsxSaxAnalyser.class);
/**
* If it's less than 5M, use map cache, or use ehcache.
*/
private static final long USE_MAP_CACHE_SIZE = 5 * 1000 * 1000L;
private AnalysisContext analysisContext; private AnalysisContext analysisContext;
private List<ReadSheet> sheetList; private List<ReadSheet> sheetList;
private Map<Integer, InputStream> sheetMap; private Map<Integer, InputStream> sheetMap;
@ -43,15 +52,32 @@ public class XlsxSaxAnalyser implements ExcelExecutor {
this.analysisContext = analysisContext; this.analysisContext = analysisContext;
// Initialize cache // Initialize cache
ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
OPCPackage pkg = readOpcPackage(readWorkbookHolder);
PackagePart sharedStringsTablePackagePart =
pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()).get(0);
if (readWorkbookHolder.getReadCache() == null) { if (readWorkbookHolder.getReadCache() == null) {
readWorkbookHolder.setReadCache(new Ehcache()); long size = sharedStringsTablePackagePart.getSize();
if (size < 0) {
size = sharedStringsTablePackagePart.getInputStream().available();
}
if (size < USE_MAP_CACHE_SIZE) {
if (LOGGER.isDebugEnabled()) {
LOGGER.info("Use map cache.size:{}", size);
}
readWorkbookHolder.setReadCache(new MapCache());
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.info("Use ehcache.size:{}", size);
}
readWorkbookHolder.setReadCache(new Ehcache());
}
} }
readWorkbookHolder.getReadCache().init(analysisContext); readWorkbookHolder.getReadCache().init(analysisContext);
OPCPackage pkg = readOpcPackage(readWorkbookHolder);
// Analysis sharedStringsTable.xml // Analysis sharedStringsTable.xml
analysisSharedStringsTable(pkg, readWorkbookHolder); analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), readWorkbookHolder);
XSSFReader xssfReader = new XSSFReader(pkg); XSSFReader xssfReader = new XSSFReader(pkg);
@ -88,10 +114,10 @@ public class XlsxSaxAnalyser implements ExcelExecutor {
} }
} }
private void analysisSharedStringsTable(OPCPackage pkg, ReadWorkbookHolder readWorkbookHolder) throws Exception { private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream,
ReadWorkbookHolder readWorkbookHolder) throws Exception {
ContentHandler handler = new SharedStringsTableHandler(readWorkbookHolder.getReadCache()); ContentHandler handler = new SharedStringsTableHandler(readWorkbookHolder.getReadCache());
parseXmlSource(pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()).get(0).getInputStream(), parseXmlSource(sharedStringsTableInputStream, handler);
handler);
readWorkbookHolder.getReadCache().putFinished(); readWorkbookHolder.getReadCache().putFinished();
} }
@ -105,7 +131,7 @@ public class XlsxSaxAnalyser implements ExcelExecutor {
File readTempFile = FileUtils.createCacheTmpFile(); File readTempFile = FileUtils.createCacheTmpFile();
readWorkbookHolder.setTempFile(readTempFile); readWorkbookHolder.setTempFile(readTempFile);
File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx"); File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx");
FileUtils.writeToFile(readTempFile, readWorkbookHolder.getInputStream()); FileUtils.writeToFile(tempFile, readWorkbookHolder.getInputStream());
return OPCPackage.open(tempFile); return OPCPackage.open(tempFile);
} }

10
src/main/java/com/alibaba/excel/metadata/CellData.java

@ -24,6 +24,15 @@ public class CellData {
private Boolean formula; private Boolean formula;
private String formulaValue; private String formulaValue;
public CellData(CellData other) {
this.type = other.type;
this.doubleValue = other.doubleValue;
this.stringValue = other.stringValue;
this.booleanValue = other.booleanValue;
this.formula = other.formula;
this.formulaValue = other.formulaValue;
}
public CellData(String stringValue) { public CellData(String stringValue) {
this(CellDataTypeEnum.STRING, stringValue); this(CellDataTypeEnum.STRING, stringValue);
} }
@ -128,4 +137,5 @@ public class CellData {
return "empty"; return "empty";
} }
} }
} }

2
src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java

@ -82,7 +82,7 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener
private Object convertValue(CellData cellData, Class clazz, ExcelContentProperty contentProperty, private Object convertValue(CellData cellData, Class clazz, ExcelContentProperty contentProperty,
Map<String, Converter> converterMap, GlobalConfiguration globalConfiguration) { Map<String, Converter> converterMap, GlobalConfiguration globalConfiguration) {
if (clazz == CellData.class) { if (clazz == CellData.class) {
return cellData; return new CellData(cellData);
} }
Converter converter = null; Converter converter = null;
if (contentProperty != null) { if (contentProperty != null) {

11
src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java

@ -3,6 +3,9 @@ package com.alibaba.excel.read.metadata.holder;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.enums.HolderEnum;
@ -17,6 +20,8 @@ import com.alibaba.excel.support.ExcelTypeEnum;
* @author zhuangjiaju * @author zhuangjiaju
*/ */
public class ReadWorkbookHolder extends AbstractReadHolder { public class ReadWorkbookHolder extends AbstractReadHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(ReadWorkbookHolder.class);
/** /**
* current param * current param
*/ */
@ -94,8 +99,14 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
} else { } else {
this.excelType = readWorkbook.getExcelType(); this.excelType = readWorkbook.getExcelType();
} }
if (ExcelTypeEnum.XLS == excelType && getGlobalConfiguration().getUse1904windowing() == null) {
getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
}
this.customObject = readWorkbook.getCustomObject(); this.customObject = readWorkbook.getCustomObject();
this.readCache = readWorkbook.getReadCache(); this.readCache = readWorkbook.getReadCache();
if (readCache != null && ExcelTypeEnum.XLS == excelType) {
LOGGER.warn("Xls not support 'readCache'!");
}
} }
public ReadWorkbook getReadWorkbook() { public ReadWorkbook getReadWorkbook() {

11
src/main/java/com/alibaba/excel/util/FileUtils.java

@ -8,6 +8,7 @@ import java.io.OutputStream;
import java.util.UUID; import java.util.UUID;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelGenerateException;
/** /**
* *
@ -24,7 +25,7 @@ public class FileUtils {
/** /**
* Write inputStream to file * Write inputStream to file
* *
* @param file * @param file
* @param inputStream * @param inputStream
*/ */
@ -65,12 +66,16 @@ public class FileUtils {
public static File createCacheTmpFile() { public static File createCacheTmpFile() {
File directory = createTmpDirectory(CACHE); File directory = createTmpDirectory(CACHE);
return new File(directory.getPath(), UUID.randomUUID().toString()); File cache = new File(directory.getPath(), UUID.randomUUID().toString());
if (!cache.mkdir()) {
throw new ExcelGenerateException("Can not create temp file!");
}
return cache;
} }
/** /**
* delete file * delete file
* *
* @param file * @param file
*/ */
public static void delete(File file) { public static void delete(File file) {

12
src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java

@ -36,10 +36,10 @@ public class ReadAllConverterData {
private Short shortBoolean; private Short shortBoolean;
private Short shortNumber; private Short shortNumber;
private Short shortString; private Short shortString;
private String StringBoolean; private String stringBoolean;
private String StringNumber; private String stringNumber;
private String StringString; private String stringString;
private String StringError; private String stringError;
private String StringFormulaNumber; private String stringFormulaNumber;
private String StringFormulaString; private String stringFormulaString;
} }

53
src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java

@ -1,5 +1,7 @@
package com.alibaba.easyexcel.test.core.converter; package com.alibaba.easyexcel.test.core.converter;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -9,6 +11,8 @@ import org.slf4j.LoggerFactory;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelCommonException;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
/** /**
@ -27,20 +31,41 @@ public class ReadAllConverterDataListener extends AnalysisEventListener<ReadAllC
public void doAfterAllAnalysed(AnalysisContext context) { public void doAfterAllAnalysed(AnalysisContext context) {
Assert.assertEquals(list.size(), 1); Assert.assertEquals(list.size(), 1);
ReadAllConverterData data = list.get(0); ReadAllConverterData data = list.get(0);
// try { Assert.assertEquals(data.getBigDecimalBoolean().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0);
// Assert.assertEquals(data.getDate(), DateUtils.parseDate("2020-01-01 01:01:01")); Assert.assertEquals(data.getBigDecimalNumber().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0);
// } catch (ParseException e) { Assert.assertEquals(data.getBigDecimalString().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0);
// throw new ExcelCommonException("Test Exception", e); Assert.assertTrue(data.getBooleanBoolean());
// } Assert.assertTrue(data.getBooleanNumber());
// Assert.assertEquals(data.getBooleanData(), Boolean.TRUE); Assert.assertTrue(data.getBooleanString());
// Assert.assertEquals(data.getBigDecimal().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0); Assert.assertEquals((long)data.getByteBoolean(), 1L);
// Assert.assertEquals((long)data.getLongData(), 1L); Assert.assertEquals((long)data.getByteNumber(), 1L);
// Assert.assertEquals((long)data.getIntegerData(), 1L); Assert.assertEquals((long)data.getByteString(), 1L);
// Assert.assertEquals((long)data.getShortData(), 1L); try {
// Assert.assertEquals((long)data.getByteData(), 1L); Assert.assertEquals(data.getDateNumber(), DateUtils.parseDate("2020-01-01 01:01:01"));
// Assert.assertEquals(data.getDoubleData(), 1.0, 0.0); Assert.assertEquals(data.getDateString(), DateUtils.parseDate("2020-01-01 01:01:01"));
// Assert.assertEquals(data.getFloatData(), (float)1.0, 0.0); } catch (ParseException e) {
// Assert.assertEquals(data.getString(), "测试"); throw new ExcelCommonException("Test Exception", e);
}
Assert.assertEquals(data.getDoubleBoolean(), 1.0, 0.0);
Assert.assertEquals(data.getDoubleNumber(), 1.0, 0.0);
Assert.assertEquals(data.getDoubleString(), 1.0, 0.0);
Assert.assertEquals(data.getFloatBoolean(), (float)1.0, 0.0);
Assert.assertEquals(data.getFloatNumber(), (float)1.0, 0.0);
Assert.assertEquals(data.getFloatString(), (float)1.0, 0.0);
Assert.assertEquals((long)data.getIntegerBoolean(), 1L);
Assert.assertEquals((long)data.getIntegerNumber(), 1L);
Assert.assertEquals((long)data.getIntegerString(), 1L);
Assert.assertEquals((long)data.getLongBoolean(), 1L);
Assert.assertEquals((long)data.getLongNumber(), 1L);
Assert.assertEquals((long)data.getLongString(), 1L);
Assert.assertEquals((long)data.getShortBoolean(), 1L);
Assert.assertEquals((long)data.getShortNumber(), 1L);
Assert.assertEquals((long)data.getShortString(), 1L);
Assert.assertEquals(data.getStringBoolean(), "true");
Assert.assertEquals(data.getStringString(), "测试");
Assert.assertEquals(data.getStringError(), "#VALUE!");
Assert.assertEquals(data.getStringFormulaNumber(), "2.0");
Assert.assertEquals(data.getStringFormulaString(), "1测试");
LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0)));
} }
} }

Loading…
Cancel
Save