Browse Source

优化读写性能

pull/2159/head
Jiaju Zhuang 3 years ago
parent
commit
b9da1ade44
  1. 2
      src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java
  2. 27
      src/main/java/com/alibaba/excel/util/ClassUtils.java
  3. 74
      src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
  4. 3
      src/test/java/com/alibaba/easyexcel/test/core/large/LargeDataTest.java

2
src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java

@ -9,6 +9,7 @@ import com.alibaba.excel.metadata.data.DataFormatData;
import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.MapUtils;
import lombok.Data; import lombok.Data;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
@ -50,6 +51,7 @@ public class XlsxReadWorkbookHolder extends ReadWorkbookHolder {
super(readWorkbook); super(readWorkbook);
this.saxParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName(); this.saxParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName();
setExcelType(ExcelTypeEnum.XLSX); setExcelType(ExcelTypeEnum.XLSX);
dataFormatDataCache = MapUtils.newHashMap();
} }
public DataFormatData dataFormatData(int dateFormatIndexInteger) { public DataFormatData dataFormatData(int dateFormatIndexInteger) {

27
src/main/java/com/alibaba/excel/util/ClassUtils.java

@ -31,6 +31,8 @@ import com.alibaba.excel.metadata.property.NumberFormatProperty;
import com.alibaba.excel.metadata.property.StyleProperty; import com.alibaba.excel.metadata.property.StyleProperty;
import com.alibaba.excel.write.metadata.holder.WriteHolder; import com.alibaba.excel.write.metadata.holder.WriteHolder;
import lombok.AllArgsConstructor;
import lombok.Data;
import net.sf.cglib.beans.BeanMap; import net.sf.cglib.beans.BeanMap;
/** /**
@ -51,7 +53,7 @@ public class ClassUtils {
/** /**
* The cache configuration information for each of the class * The cache configuration information for each of the class
*/ */
public static final Map<String, ExcelContentProperty> CONTENT_CACHE = new ConcurrentHashMap<>(); public static final Map<ContentPropertyKey, ExcelContentProperty> CONTENT_CACHE = new ConcurrentHashMap<>();
/** /**
* Calculate the configuration information for the class * Calculate the configuration information for the class
@ -117,20 +119,8 @@ public class ClassUtils {
} }
} }
private static String buildKey(Class<?> clazz, Class<?> headClass, String fieldName) { private static ContentPropertyKey buildKey(Class<?> clazz, Class<?> headClass, String fieldName) {
String key = ""; return new ContentPropertyKey(clazz, headClass, fieldName);
if (clazz != null) {
key += clazz.getName();
}
key += "-";
if (headClass != null) {
key += headClass.getName();
}
key += "-";
if (fieldName != null) {
key += fieldName;
}
return key;
} }
private static Map<String, ExcelContentProperty> declaredFieldContentMap(Class<?> clazz) { private static Map<String, ExcelContentProperty> declaredFieldContentMap(Class<?> clazz) {
@ -413,4 +403,11 @@ public class ClassUtils {
} }
} }
@Data
@AllArgsConstructor
public static class ContentPropertyKey {
private Class<?> clazz;
private Class<?> headClass;
private String fieldName;
}
} }

74
src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java

@ -7,6 +7,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -31,6 +32,8 @@ import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper; import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.usermodel.PoiUtils; import org.apache.poi.hssf.usermodel.PoiUtils;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
@ -55,29 +58,30 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
/** /**
* Fields to replace in the template * Fields to replace in the template
*/ */
private final Map<String, List<AnalysisCell>> templateAnalysisCache = MapUtils.newHashMap(); private final Map<UniqueDataFlagKey, List<AnalysisCell>> templateAnalysisCache = MapUtils.newHashMap();
/** /**
* Collection fields to replace in the template * Collection fields to replace in the template
*/ */
private final Map<String, List<AnalysisCell>> templateCollectionAnalysisCache = MapUtils.newHashMap(); private final Map<UniqueDataFlagKey, List<AnalysisCell>> templateCollectionAnalysisCache = MapUtils.newHashMap();
/** /**
* Style cache for collection fields * Style cache for collection fields
*/ */
private final Map<String, Map<AnalysisCell, CellStyle>> collectionFieldStyleCache = MapUtils.newHashMap(); private final Map<UniqueDataFlagKey, Map<AnalysisCell, CellStyle>> collectionFieldStyleCache
= MapUtils.newHashMap();
/** /**
* Row height cache for collection * Row height cache for collection
*/ */
private final Map<String, Short> collectionRowHeightCache = MapUtils.newHashMap(); private final Map<UniqueDataFlagKey, Short> collectionRowHeightCache = MapUtils.newHashMap();
/** /**
* Last index cache for collection fields * Last index cache for collection fields
*/ */
private final Map<String, Map<AnalysisCell, Integer>> collectionLastIndexCache = MapUtils.newHashMap(); private final Map<UniqueDataFlagKey, Map<AnalysisCell, Integer>> collectionLastIndexCache = MapUtils.newHashMap();
private final Map<String, Integer> relativeRowIndexMap = MapUtils.newHashMap(); private final Map<UniqueDataFlagKey, Integer> relativeRowIndexMap = MapUtils.newHashMap();
/** /**
* The unique data encoding for this fill * The unique data encoding for this fill
*/ */
private String currentUniqueDataFlag; private UniqueDataFlagKey currentUniqueDataFlag;
public ExcelWriteFillExecutor(WriteContext writeContext) { public ExcelWriteFillExecutor(WriteContext writeContext) {
super(writeContext); super(writeContext);
@ -161,15 +165,16 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
sheet.shiftRows(maxRowIndex + 1, lastRowIndex, number, true, false); sheet.shiftRows(maxRowIndex + 1, lastRowIndex, number, true, false);
// The current data is greater than unity rowindex increase // The current data is greater than unity rowindex increase
String tablePrefix = tablePrefix(currentUniqueDataFlag); increaseRowIndex(templateAnalysisCache, number, maxRowIndex);
increaseRowIndex(templateAnalysisCache, number, maxRowIndex, tablePrefix); increaseRowIndex(templateCollectionAnalysisCache, number, maxRowIndex);
increaseRowIndex(templateCollectionAnalysisCache, number, maxRowIndex, tablePrefix);
} }
private void increaseRowIndex(Map<String, List<AnalysisCell>> templateAnalysisCache, int number, int maxRowIndex, private void increaseRowIndex(Map<UniqueDataFlagKey, List<AnalysisCell>> templateAnalysisCache, int number,
String tablePrefix) { int maxRowIndex) {
for (Map.Entry<String, List<AnalysisCell>> entry : templateAnalysisCache.entrySet()) { for (Map.Entry<UniqueDataFlagKey, List<AnalysisCell>> entry : templateAnalysisCache.entrySet()) {
if (!tablePrefix.equals(tablePrefix(entry.getKey()))) { UniqueDataFlagKey uniqueDataFlagKey = entry.getKey();
if (!Objects.equals(currentUniqueDataFlag.getSheetNo(), uniqueDataFlagKey.getSheetNo()) || !Objects.equals(
currentUniqueDataFlag.getSheetName(), uniqueDataFlagKey.getSheetName())) {
continue; continue;
} }
for (AnalysisCell analysisCell : entry.getValue()) { for (AnalysisCell analysisCell : entry.getValue()) {
@ -191,7 +196,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
} else { } else {
dataMap = BeanMapUtils.create(oneRowData); dataMap = BeanMapUtils.create(oneRowData);
} }
Set<String> dataKeySet = new HashSet<String>(dataMap.keySet()); Set<String> dataKeySet = new HashSet<>(dataMap.keySet());
for (AnalysisCell analysisCell : analysisCellList) { for (AnalysisCell analysisCell : analysisCellList) {
CellWriteHandlerContext cellWriteHandlerContext = WriteHandlerUtils.createCellWriteHandlerContext( CellWriteHandlerContext cellWriteHandlerContext = WriteHandlerUtils.createCellWriteHandlerContext(
@ -337,8 +342,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
throw new ExcelGenerateException("The wrong direction."); throw new ExcelGenerateException("The wrong direction.");
} }
Row row = createRowIfNecessary(sheet, cachedSheet, lastRowIndex, fillConfig, analysisCell, isOriginalCell, Row row = createRowIfNecessary(sheet, cachedSheet, lastRowIndex, fillConfig, analysisCell, isOriginalCell);
cellWriteHandlerContext);
cellWriteHandlerContext.setRow(row); cellWriteHandlerContext.setRow(row);
cellWriteHandlerContext.setRowIndex(lastRowIndex); cellWriteHandlerContext.setRowIndex(lastRowIndex);
@ -368,7 +372,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
} }
private Row createRowIfNecessary(Sheet sheet, Sheet cachedSheet, Integer lastRowIndex, FillConfig fillConfig, private Row createRowIfNecessary(Sheet sheet, Sheet cachedSheet, Integer lastRowIndex, FillConfig fillConfig,
AnalysisCell analysisCell, boolean isOriginalCell, CellWriteHandlerContext cellWriteHandlerContext) { AnalysisCell analysisCell, boolean isOriginalCell) {
Row row = sheet.getRow(lastRowIndex); Row row = sheet.getRow(lastRowIndex);
if (row != null) { if (row != null) {
checkRowHeight(analysisCell, fillConfig, isOriginalCell, row); checkRowHeight(analysisCell, fillConfig, isOriginalCell, row);
@ -419,13 +423,13 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
} }
} }
private List<AnalysisCell> readTemplateData(Map<String, List<AnalysisCell>> analysisCache) { private List<AnalysisCell> readTemplateData(Map<UniqueDataFlagKey, List<AnalysisCell>> analysisCache) {
List<AnalysisCell> analysisCellList = analysisCache.get(currentUniqueDataFlag); List<AnalysisCell> analysisCellList = analysisCache.get(currentUniqueDataFlag);
if (analysisCellList != null) { if (analysisCellList != null) {
return analysisCellList; return analysisCellList;
} }
Sheet sheet = writeContext.writeSheetHolder().getCachedSheet(); Sheet sheet = writeContext.writeSheetHolder().getCachedSheet();
Map<String, Set<Integer>> firstRowCache = MapUtils.newHashMapWithExpectedSize(8); Map<UniqueDataFlagKey, Set<Integer>> firstRowCache = MapUtils.newHashMapWithExpectedSize(8);
for (int i = 0; i <= sheet.getLastRowNum(); i++) { for (int i = 0; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i); Row row = sheet.getRow(i);
if (row == null) { if (row == null) {
@ -455,7 +459,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
* @param firstRowCache first row cache * @param firstRowCache first row cache
* @return Returns the data that the cell needs to replace * @return Returns the data that the cell needs to replace
*/ */
private String prepareData(Cell cell, int rowIndex, int columnIndex, Map<String, Set<Integer>> firstRowCache) { private String prepareData(Cell cell, int rowIndex, int columnIndex,
Map<UniqueDataFlagKey, Set<Integer>> firstRowCache) {
if (!CellType.STRING.equals(cell.getCellType())) { if (!CellType.STRING.equals(cell.getCellType())) {
return null; return null;
} }
@ -538,7 +543,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
} }
private String dealAnalysisCell(AnalysisCell analysisCell, String value, int rowIndex, int lastPrepareDataIndex, private String dealAnalysisCell(AnalysisCell analysisCell, String value, int rowIndex, int lastPrepareDataIndex,
int length, Map<String, Set<Integer>> firstRowCache, StringBuilder preparedData) { int length, Map<UniqueDataFlagKey, Set<Integer>> firstRowCache, StringBuilder preparedData) {
if (analysisCell != null) { if (analysisCell != null) {
if (lastPrepareDataIndex == length) { if (lastPrepareDataIndex == length) {
analysisCell.getPrepareDataList().add(StringUtils.EMPTY); analysisCell.getPrepareDataList().add(StringUtils.EMPTY);
@ -546,7 +551,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
analysisCell.getPrepareDataList().add(convertPrepareData(value.substring(lastPrepareDataIndex))); analysisCell.getPrepareDataList().add(convertPrepareData(value.substring(lastPrepareDataIndex)));
analysisCell.setOnlyOneVariable(Boolean.FALSE); analysisCell.setOnlyOneVariable(Boolean.FALSE);
} }
String uniqueDataFlag = uniqueDataFlag(writeContext.writeSheetHolder(), analysisCell.getPrefix()); UniqueDataFlagKey uniqueDataFlag = uniqueDataFlag(writeContext.writeSheetHolder(),
analysisCell.getPrefix());
if (WriteTemplateAnalysisCellTypeEnum.COMMON.equals(analysisCell.getCellType())) { if (WriteTemplateAnalysisCellTypeEnum.COMMON.equals(analysisCell.getCellType())) {
List<AnalysisCell> analysisCellList = templateAnalysisCache.computeIfAbsent(uniqueDataFlag, List<AnalysisCell> analysisCellList = templateAnalysisCache.computeIfAbsent(uniqueDataFlag,
key -> ListUtils.newArrayList()); key -> ListUtils.newArrayList());
@ -590,21 +596,15 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
return prepareData; return prepareData;
} }
private String uniqueDataFlag(WriteSheetHolder writeSheetHolder, String wrapperName) { private UniqueDataFlagKey uniqueDataFlag(WriteSheetHolder writeSheetHolder, String wrapperName) {
String prefix; return new UniqueDataFlagKey(writeSheetHolder.getSheetNo(), writeSheetHolder.getSheetName(), wrapperName);
if (writeSheetHolder.getSheetNo() != null) {
prefix = writeSheetHolder.getSheetNo().toString();
} else {
prefix = writeSheetHolder.getSheetName();
}
if (StringUtils.isEmpty(wrapperName)) {
return prefix + "-";
}
return prefix + "-" + wrapperName;
} }
private String tablePrefix(String uniqueDataFlag) { @Data
return uniqueDataFlag.substring(0, uniqueDataFlag.indexOf("-") + 1); @AllArgsConstructor
public static class UniqueDataFlagKey {
private Integer sheetNo;
private String sheetName;
private String wrapperName;
} }
} }

3
src/test/java/com/alibaba/easyexcel/test/core/large/LargeDataTest.java

@ -46,7 +46,8 @@ public class LargeDataTest {
} }
@Test @Test
public void t01Read() { public void t01Read() throws Exception{
Thread.sleep(10*1000L);
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
EasyExcel.read(TestFileUtil.getPath() + "large" + File.separator + "large07.xlsx", LargeData.class, EasyExcel.read(TestFileUtil.getPath() + "large" + File.separator + "large07.xlsx", LargeData.class,
new LargeDataListener()).headRowNumber(2).sheet().doRead(); new LargeDataListener()).headRowNumber(2).sheet().doRead();

Loading…
Cancel
Save