diff --git a/README.md b/README.md index 0622245..ecd2000 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ easyexcel [QQ群: 662022184](//shang.qq.com/wpa/qunwpa?idkey=53d9d821b0833e3c14670f007488a61e300f00ff4f1b81fd950590d90dd80f80) [钉钉群: 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11) [官方网站: https://alibaba-easyexcel.github.io/](https://alibaba-easyexcel.github.io/) +#### 因为公司不方便用QQ,所以建议加钉钉群 # JAVA解析Excel工具easyexcel Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java index 2f35435..fe5a642 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java @@ -24,7 +24,8 @@ public class CellTagHandler extends AbstractXlsxTagHandler { @Override public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); - xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R))); + xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R), + xlsxReadSheetHolder.getColumnIndex())); // t="s" ,it's means String // t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml' diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java index 56fa7ae..61f3873 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java @@ -9,6 +9,7 @@ import com.alibaba.excel.context.xlsx.XlsxReadContext; import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.Cell; import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.util.PositionUtils; /** @@ -20,27 +21,31 @@ public class RowTagHandler extends AbstractXlsxTagHandler { @Override public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { - int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R)); - Integer lastIndex = xlsxReadContext.readSheetHolder().getRowIndex(); - if (lastIndex != null) { - while (lastIndex + 1 < rowIndex) { - xlsxReadContext.readRowHolder(new ReadRowHolder(lastIndex + 1, RowTypeEnum.EMPTY, - xlsxReadContext.readSheetHolder().getGlobalConfiguration(), new LinkedHashMap())); + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R), + xlsxReadSheetHolder.getRowIndex()); + Integer lastRowIndex = xlsxReadContext.readSheetHolder().getRowIndex(); + if (lastRowIndex != null) { + while (lastRowIndex + 1 < rowIndex) { + xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY, + xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap())); xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); - xlsxReadContext.xlsxReadSheetHolder().setCellMap(new LinkedHashMap()); - lastIndex++; + xlsxReadSheetHolder.setColumnIndex(null); + xlsxReadSheetHolder.setCellMap(new LinkedHashMap()); + lastRowIndex++; } } - xlsxReadContext.readSheetHolder().setRowIndex(rowIndex); + xlsxReadSheetHolder.setRowIndex(rowIndex); } @Override public void endElement(XlsxReadContext xlsxReadContext, String name) { - xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadContext.readSheetHolder().getRowIndex(), - RowTypeEnum.DATA, xlsxReadContext.readSheetHolder().getGlobalConfiguration(), - xlsxReadContext.xlsxReadSheetHolder().getCellMap())); + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadSheetHolder.getRowIndex(), RowTypeEnum.DATA, + xlsxReadSheetHolder.getGlobalConfiguration(), xlsxReadSheetHolder.getCellMap())); xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); - xlsxReadContext.xlsxReadSheetHolder().setCellMap(new LinkedHashMap()); + xlsxReadSheetHolder.setColumnIndex(null); + xlsxReadSheetHolder.setCellMap(new LinkedHashMap()); } } diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index 77ba7ec..8465cbd 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -108,34 +108,39 @@ public class WriteContextImpl implements WriteContext { if (writeSheet == null) { throw new IllegalArgumentException("Sheet argument cannot be null"); } - if (writeSheet.getSheetNo() == null || writeSheet.getSheetNo() <= 0) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Sheet number is null"); - } - writeSheet.setSheetNo(0); - } - if (writeWorkbookHolder.getHasBeenInitializedSheet().containsKey(writeSheet.getSheetNo())) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Sheet:{} is already existed", writeSheet.getSheetNo()); - } - writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheet().get(writeSheet.getSheetNo()); - writeSheetHolder.setNewInitialization(Boolean.FALSE); - writeTableHolder = null; - currentWriteHolder = writeSheetHolder; - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("CurrentConfiguration is writeSheetHolder"); - } + if (selectSheetFromCache(writeSheet)) { return; } initCurrentSheetHolder(writeSheet); - WriteHandlerUtils.beforeSheetCreate(this); // Initialization current sheet initSheet(writeType); } + private boolean selectSheetFromCache(WriteSheet writeSheet) { + writeSheetHolder = null; + if (writeSheet.getSheetNo() != null) { + writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().get(writeSheet.getSheetNo()); + } + if (writeSheetHolder == null && !StringUtils.isEmpty(writeSheet.getSheetName())) { + writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetNameMap().get(writeSheet.getSheetName()); + } + if (writeSheetHolder == null) { + return false; + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Sheet:{} is already existed", writeSheet.getSheetNo()); + } + writeSheetHolder.setNewInitialization(Boolean.FALSE); + writeTableHolder = null; + currentWriteHolder = writeSheetHolder; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("CurrentConfiguration is writeSheetHolder"); + } + return true; + } + private void initCurrentSheetHolder(WriteSheet writeSheet) { writeSheetHolder = new WriteSheetHolder(writeSheet, writeWorkbookHolder); - writeWorkbookHolder.getHasBeenInitializedSheet().put(writeSheet.getSheetNo(), writeSheetHolder); writeTableHolder = null; currentWriteHolder = writeSheetHolder; if (LOGGER.isDebugEnabled()) { @@ -144,17 +149,24 @@ public class WriteContextImpl implements WriteContext { } private void initSheet(WriteTypeEnum writeType) { + WriteHandlerUtils.beforeSheetCreate(this); Sheet currentSheet; try { - currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); - writeSheetHolder - .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo())); - } catch (Exception e) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo()); + if (writeSheetHolder.getSheetNo() != null) { + currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); + writeSheetHolder + .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo())); + } else { + // sheet name must not null + currentSheet = writeWorkbookHolder.getWorkbook().getSheet(writeSheetHolder.getSheetName()); + writeSheetHolder + .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheet(writeSheetHolder.getSheetName())); } - currentSheet = WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName()); - writeSheetHolder.setCachedSheet(currentSheet); + } catch (Exception e) { + currentSheet = createSheet(); + } + if (currentSheet == null) { + currentSheet = createSheet(); } writeSheetHolder.setSheet(currentSheet); WriteHandlerUtils.afterSheetCreate(this); @@ -162,6 +174,21 @@ public class WriteContextImpl implements WriteContext { // Initialization head initHead(writeSheetHolder.excelWriteHeadProperty()); } + writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().put(writeSheetHolder.getSheetNo(), writeSheetHolder); + writeWorkbookHolder.getHasBeenInitializedSheetNameMap().put(writeSheetHolder.getSheetName(), writeSheetHolder); + } + + private Sheet createSheet() { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo()); + } + if (StringUtils.isEmpty(writeSheetHolder.getSheetName())) { + writeSheetHolder.setSheetName(writeSheetHolder.getSheetNo().toString()); + } + Sheet currentSheet = + WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName()); + writeSheetHolder.setCachedSheet(currentSheet); + return currentSheet; } public void initHead(ExcelWriteHeadProperty excelWriteHeadProperty) { diff --git a/src/main/java/com/alibaba/excel/util/PositionUtils.java b/src/main/java/com/alibaba/excel/util/PositionUtils.java index f135e47..a527ae1 100644 --- a/src/main/java/com/alibaba/excel/util/PositionUtils.java +++ b/src/main/java/com/alibaba/excel/util/PositionUtils.java @@ -15,6 +15,20 @@ public class PositionUtils { return row; } + public static int getRowByRowTagt(String rowTagt, Integer before) { + int row; + if (rowTagt != null) { + row = Integer.parseInt(rowTagt) - 1; + return row; + } else { + if (before == null) { + before = -1; + } + return before + 1; + } + + } + public static int getRow(String currentCellIndex) { int row = 0; if (currentCellIndex != null) { @@ -35,4 +49,22 @@ public class PositionUtils { } return col - 1; } + + public static int getCol(String currentCellIndex, Integer before) { + int col = 0; + if (currentCellIndex != null) { + + char[] currentIndex = currentCellIndex.replaceAll("[0-9]", "").toCharArray(); + for (int i = 0; i < currentIndex.length; i++) { + col += (currentIndex[i] - '@') * Math.pow(26, (currentIndex.length - i - 1)); + } + return col - 1; + } else { + if (before == null) { + before = -1; + } + return before + 1; + } + } + } diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java index 90030f4..56fc7e4 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java @@ -10,6 +10,7 @@ import org.apache.poi.xssf.usermodel.XSSFSheet; import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.enums.WriteLastRowTypeEnum; +import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.write.metadata.WriteSheet; /** @@ -67,12 +68,12 @@ public class WriteSheetHolder extends AbstractWriteHolder { public WriteSheetHolder(WriteSheet writeSheet, WriteWorkbookHolder writeWorkbookHolder) { super(writeSheet, writeWorkbookHolder, writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled()); this.writeSheet = writeSheet; - this.sheetNo = writeSheet.getSheetNo(); - if (writeSheet.getSheetName() == null) { - this.sheetName = writeSheet.getSheetNo().toString(); + if (writeSheet.getSheetNo() == null && StringUtils.isEmpty(writeSheet.getSheetName())) { + this.sheetNo = 0; } else { - this.sheetName = writeSheet.getSheetName(); + this.sheetNo = writeSheet.getSheetNo(); } + this.sheetName = writeSheet.getSheetName(); this.parentWriteWorkbookHolder = writeWorkbookHolder; this.hasBeenInitializedTable = new HashMap(); if (writeWorkbookHolder.getTempTemplateInputStream() != null) { diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java index c8f7555..be557eb 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java @@ -92,7 +92,11 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { /** * prevent duplicate creation of sheet objects */ - private Map hasBeenInitializedSheet; + private Map hasBeenInitializedSheetIndexMap; + /** + * prevent duplicate creation of sheet objects + */ + private Map hasBeenInitializedSheetNameMap; /** * Whether the encryption */ @@ -148,7 +152,8 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { } else { this.mandatoryUseInputStream = writeWorkbook.getMandatoryUseInputStream(); } - this.hasBeenInitializedSheet = new HashMap(); + this.hasBeenInitializedSheetIndexMap = new HashMap(); + this.hasBeenInitializedSheetNameMap = new HashMap(); this.password = writeWorkbook.getPassword(); if (writeWorkbook.getInMemory() == null) { this.inMemory = Boolean.FALSE; @@ -197,12 +202,20 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { this.cachedWorkbook = cachedWorkbook; } - public Map getHasBeenInitializedSheet() { - return hasBeenInitializedSheet; + public Map getHasBeenInitializedSheetIndexMap() { + return hasBeenInitializedSheetIndexMap; + } + + public void setHasBeenInitializedSheetIndexMap(Map hasBeenInitializedSheetIndexMap) { + this.hasBeenInitializedSheetIndexMap = hasBeenInitializedSheetIndexMap; + } + + public Map getHasBeenInitializedSheetNameMap() { + return hasBeenInitializedSheetNameMap; } - public void setHasBeenInitializedSheet(Map hasBeenInitializedSheet) { - this.hasBeenInitializedSheet = hasBeenInitializedSheet; + public void setHasBeenInitializedSheetNameMap(Map hasBeenInitializedSheetNameMap) { + this.hasBeenInitializedSheetNameMap = hasBeenInitializedSheetNameMap; } public WriteWorkbook getWriteWorkbook() { diff --git a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java index bdcd34c..a3e2463 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java @@ -40,6 +40,10 @@ public class FillDataTest { private static File horizontalFillTemplate07; private static File fileHorizontal03; private static File horizontalFillTemplate03; + private static File byName07; + private static File byName03; + private static File byNameTemplate07; + private static File byNameTemplate03; private static File fileComposite07; private static File compositeFillTemplate07; private static File fileComposite03; @@ -59,6 +63,10 @@ public class FillDataTest { horizontalFillTemplate07 = TestFileUtil.readFile("fill" + File.separator + "horizontal.xlsx"); fileHorizontal03 = TestFileUtil.createNewFile("fillHorizontal03.xls"); horizontalFillTemplate03 = TestFileUtil.readFile("fill" + File.separator + "horizontal.xls"); + byName07 = TestFileUtil.createNewFile("byName07.xlsx"); + byNameTemplate07 = TestFileUtil.readFile("fill" + File.separator + "byName.xlsx"); + byName03 = TestFileUtil.createNewFile("byName03.xls"); + byNameTemplate03 = TestFileUtil.readFile("fill" + File.separator + "byName.xls"); fileComposite07 = TestFileUtil.createNewFile("fileComposite07.xlsx"); compositeFillTemplate07 = TestFileUtil.readFile("fill" + File.separator + "composite.xlsx"); fileComposite03 = TestFileUtil.createNewFile("fileComposite03.xls"); @@ -95,6 +103,23 @@ public class FillDataTest { horizontalFill(fileHorizontal03, horizontalFillTemplate03); } + @Test + public void t07ByNameFill07() { + byNameFill(byName07, byNameTemplate07); + } + + @Test + public void t08ByNameFill03() { + byNameFill(byName03, byNameTemplate03); + } + + private void byNameFill(File file, File template) { + FillData fillData = new FillData(); + fillData.setName("张三"); + fillData.setNumber(5.2); + EasyExcel.write(file, FillData.class).withTemplate(template).sheet("Sheet2").doFill(fillData); + } + @Test public void t07CompositeFill07() { compositeFill(fileComposite07, compositeFillTemplate07); diff --git a/src/test/resources/fill/byName.xls b/src/test/resources/fill/byName.xls new file mode 100644 index 0000000..e07fd50 Binary files /dev/null and b/src/test/resources/fill/byName.xls differ diff --git a/src/test/resources/fill/byName.xlsx b/src/test/resources/fill/byName.xlsx new file mode 100644 index 0000000..327e055 Binary files /dev/null and b/src/test/resources/fill/byName.xlsx differ diff --git a/update.md b/update.md index 0d34e83..834bee6 100644 --- a/update.md +++ b/update.md @@ -15,6 +15,13 @@ * 修复读取转换器的并发问题 * 填充支持多个List对象 +# 2.1.6 +* 修复写入只有`sheetName`会抛异常 + +# 2.1.5 +* 修复部分xlsx没有行号读取异常 +* 填充时候支持根据`sheetName`定位`sheet` + # 2.1.4 * 新增参数`useDefaultListener` 可以排除默认对象转换