Browse Source

优化读写逻辑

developing
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() {
try {
ExcelTypeEnum excelType = analysisContext.readWorkbookHolder().getExcelType();
if (excelType == null) {
private void choiceExcelExecutor() throws Exception {
ExcelTypeEnum excelType = analysisContext.readWorkbookHolder().getExcelType();
if (excelType == null) {
excelExecutor = new XlsxSaxAnalyser(analysisContext);
return;
}
switch (excelType) {
case XLS:
excelExecutor = new XlsSaxAnalyser(analysisContext);
break;
case XLSX:
excelExecutor = new XlsxSaxAnalyser(analysisContext);
return;
}
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);
break;
default:
}
}

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

@ -1,12 +1,17 @@
package com.alibaba.excel.analysis.v03.handlers;
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.Record;
import org.apache.poi.hssf.record.StringRecord;
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.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
@ -15,9 +20,13 @@ import com.alibaba.excel.metadata.CellData;
* @author Dan Zheng
*/
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 nextColumn;
private boolean outputNextStringRecord;
private CellData tempCellData;
private FormatTrackingHSSFListener formatListener;
private HSSFWorkbook stubWorkbook;
@ -38,24 +47,56 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler {
this.row = frec.getRow();
this.column = frec.getColumn();
if (Double.isNaN(frec.getValue())) {
// Formula result is a string
// This is stored in the next record
outputNextStringRecord = true;
nextRow = frec.getRow();
nextColumn = frec.getColumn();
} else {
this.cellData = new CellData(frec.getValue());
CellType cellType = CellType.forInt(frec.getCachedResultType());
String formulaValue = null;
try {
formulaValue = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
} catch (Exception e) {
LOGGER.warn("Get formula value error.{}", e.getMessage());
}
switch (cellType) {
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) {
if (outputNextStringRecord) {
// String for formula
StringRecord srec = (StringRecord)record;
this.cellData = new CellData(srec.getString());
this.cellData = tempCellData;
this.cellData.setStringValue(srec.getString());
this.row = nextRow;
this.column = nextColumn;
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 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.usermodel.XSSFRelation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
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.InputSource;
import org.xml.sax.XMLReader;
import com.alibaba.excel.analysis.ExcelExecutor;
import com.alibaba.excel.cache.Ehcache;
import com.alibaba.excel.cache.MapCache;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.read.metadata.ReadSheet;
@ -35,6 +39,11 @@ import com.alibaba.excel.util.FileUtils;
* @author jipengfei
*/
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 List<ReadSheet> sheetList;
private Map<Integer, InputStream> sheetMap;
@ -43,15 +52,32 @@ public class XlsxSaxAnalyser implements ExcelExecutor {
this.analysisContext = analysisContext;
// Initialize cache
ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
OPCPackage pkg = readOpcPackage(readWorkbookHolder);
PackagePart sharedStringsTablePackagePart =
pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()).get(0);
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);
OPCPackage pkg = readOpcPackage(readWorkbookHolder);
// Analysis sharedStringsTable.xml
analysisSharedStringsTable(pkg, readWorkbookHolder);
analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), readWorkbookHolder);
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());
parseXmlSource(pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()).get(0).getInputStream(),
handler);
parseXmlSource(sharedStringsTableInputStream, handler);
readWorkbookHolder.getReadCache().putFinished();
}
@ -105,7 +131,7 @@ public class XlsxSaxAnalyser implements ExcelExecutor {
File readTempFile = FileUtils.createCacheTmpFile();
readWorkbookHolder.setTempFile(readTempFile);
File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx");
FileUtils.writeToFile(readTempFile, readWorkbookHolder.getInputStream());
FileUtils.writeToFile(tempFile, readWorkbookHolder.getInputStream());
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 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) {
this(CellDataTypeEnum.STRING, stringValue);
}
@ -128,4 +137,5 @@ public class CellData {
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,
Map<String, Converter> converterMap, GlobalConfiguration globalConfiguration) {
if (clazz == CellData.class) {
return cellData;
return new CellData(cellData);
}
Converter converter = 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.InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.HolderEnum;
@ -17,6 +20,8 @@ import com.alibaba.excel.support.ExcelTypeEnum;
* @author zhuangjiaju
*/
public class ReadWorkbookHolder extends AbstractReadHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(ReadWorkbookHolder.class);
/**
* current param
*/
@ -94,8 +99,14 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
} else {
this.excelType = readWorkbook.getExcelType();
}
if (ExcelTypeEnum.XLS == excelType && getGlobalConfiguration().getUse1904windowing() == null) {
getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
}
this.customObject = readWorkbook.getCustomObject();
this.readCache = readWorkbook.getReadCache();
if (readCache != null && ExcelTypeEnum.XLS == excelType) {
LOGGER.warn("Xls not support 'readCache'!");
}
}
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 com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelGenerateException;
/**
*
@ -24,7 +25,7 @@ public class FileUtils {
/**
* Write inputStream to file
*
*
* @param file
* @param inputStream
*/
@ -65,12 +66,16 @@ public class FileUtils {
public static File createCacheTmpFile() {
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
*
*
* @param 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 shortNumber;
private Short shortString;
private String StringBoolean;
private String StringNumber;
private String StringString;
private String StringError;
private String StringFormulaNumber;
private String StringFormulaString;
private String stringBoolean;
private String stringNumber;
private String stringString;
private String stringError;
private String stringFormulaNumber;
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;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
@ -9,6 +11,8 @@ import org.slf4j.LoggerFactory;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelCommonException;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.fastjson.JSON;
/**
@ -27,20 +31,41 @@ public class ReadAllConverterDataListener extends AnalysisEventListener<ReadAllC
public void doAfterAllAnalysed(AnalysisContext context) {
Assert.assertEquals(list.size(), 1);
ReadAllConverterData data = list.get(0);
// try {
// Assert.assertEquals(data.getDate(), DateUtils.parseDate("2020-01-01 01:01:01"));
// } catch (ParseException e) {
// throw new ExcelCommonException("Test Exception", e);
// }
// Assert.assertEquals(data.getBooleanData(), Boolean.TRUE);
// Assert.assertEquals(data.getBigDecimal().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0);
// Assert.assertEquals((long)data.getLongData(), 1L);
// Assert.assertEquals((long)data.getIntegerData(), 1L);
// Assert.assertEquals((long)data.getShortData(), 1L);
// Assert.assertEquals((long)data.getByteData(), 1L);
// Assert.assertEquals(data.getDoubleData(), 1.0, 0.0);
// Assert.assertEquals(data.getFloatData(), (float)1.0, 0.0);
// Assert.assertEquals(data.getString(), "测试");
Assert.assertEquals(data.getBigDecimalBoolean().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0);
Assert.assertEquals(data.getBigDecimalNumber().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0);
Assert.assertEquals(data.getBigDecimalString().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0);
Assert.assertTrue(data.getBooleanBoolean());
Assert.assertTrue(data.getBooleanNumber());
Assert.assertTrue(data.getBooleanString());
Assert.assertEquals((long)data.getByteBoolean(), 1L);
Assert.assertEquals((long)data.getByteNumber(), 1L);
Assert.assertEquals((long)data.getByteString(), 1L);
try {
Assert.assertEquals(data.getDateNumber(), DateUtils.parseDate("2020-01-01 01:01:01"));
Assert.assertEquals(data.getDateString(), DateUtils.parseDate("2020-01-01 01:01:01"));
} catch (ParseException e) {
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)));
}
}

Loading…
Cancel
Save