diff --git a/.github/ISSUE_TEMPLATE/1question.md b/.github/ISSUE_TEMPLATE/1question.md deleted file mode 100644 index bb30c518..00000000 --- a/.github/ISSUE_TEMPLATE/1question.md +++ /dev/null @@ -1,18 +0,0 @@ -name: 使用疑问 -about: 请先阅读“快速使用”,上面无法解决再提交问题 -name: 给出建议 -about: 给出一些建议的能 -title: '' -labels: help wanted -labels: suggest -assignees: '' - ---- - -**异常代码** -```java - 这里写你的代码 -``` -**异常提示** -请提供完整的异常提示 -**建议描述** \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5bf10d7a..3241410a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.0.0-beta3 + 2.0.0-beta4 jar easyexcel diff --git a/quickstart.md b/quickstart.md index e84d0705..3e5dd00b 100644 --- a/quickstart.md +++ b/quickstart.md @@ -13,6 +13,7 @@ * ExcelReaderSheetBuilder ExcelWriterSheetBuilder 构建出一个 ReadSheet WriteSheet对象,可以理解成excel里面的一页,每一页都要构建一个 * ReadListener 在每一行读取完毕后都会调用ReadListener来处理数据 * WriteHandler 在每一个操作包括创建单元格、创建表格等都会调用WriteHandler来处理数据 +* 所有配置都是继承的,Workbook的配置会被Sheet继承,所以在用EasyExcel设置参数的时候,在EasyExcel...sheet()方法之前作用域是整个sheet,之后针对单个sheet #### 开源项目不容易,如果觉得本项目对您的工作还是有帮助的话,请在右上角帮忙点个★Star。 ### 读 DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/demo/read/ReadTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java) diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index a5072a1d..ddabd8cc 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -14,6 +14,8 @@ import org.apache.poi.hssf.eventusermodel.HSSFListener; import org.apache.poi.hssf.eventusermodel.HSSFRequest; import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; @@ -83,6 +85,7 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelExecutor { @Override public void execute() { + analysisContext.readSheetHolder().getSheetNo(); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); formatListener = new FormatTrackingHSSFListener(listener); workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); @@ -121,6 +124,10 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelExecutor { @Override public void processRecord(Record record) { + // Not data from the current sheet + if (ignoreRecord(record)) { + return; + } int thisRow = -1; int thisColumn = -1; CellData cellData = null; @@ -164,6 +171,11 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelExecutor { processLastCellOfRow(record); } + private boolean ignoreRecord(Record record) { + return analysisContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid + && record.getSid() != BOFRecord.sid; + } + private void processLastCellOfRow(Record record) { // Handle end of row if (record instanceof LastCellOfRowDummyRecord) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java index da5967d4..324d3e3e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -23,7 +23,6 @@ public class BofRecordHandler extends AbstractXlsRecordHandler { private int sheetIndex; private List sheets; private AnalysisContext context; - private boolean analyAllSheet; private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; public BofRecordHandler(EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener, @@ -48,21 +47,20 @@ public class BofRecordHandler extends AbstractXlsRecordHandler { if (orderedBsrs == null) { orderedBsrs = BoundSheetRecord.orderByBofPosition(boundSheetRecords); } - sheetIndex++; - ReadSheet readSheet = new ReadSheet(sheetIndex, orderedBsrs[sheetIndex - 1].getSheetname()); + ReadSheet readSheet = new ReadSheet(sheetIndex, orderedBsrs[sheetIndex].getSheetname()); sheets.add(readSheet); - if (this.analyAllSheet) { - context.currentSheet(null, readSheet); + if (sheetIndex == context.readSheetHolder().getSheetNo()) { + context.readWorkbookHolder().setIgnoreRecord03(Boolean.FALSE); + } else { + context.readWorkbookHolder().setIgnoreRecord03(Boolean.TRUE); } + sheetIndex++; } } } @Override public void init() { - if (context.readSheetHolder() == null) { - this.analyAllSheet = true; - } sheetIndex = 0; orderedBsrs = null; boundSheetRecords.clear(); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java index cca10f65..957dd91c 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java @@ -13,6 +13,11 @@ import com.alibaba.excel.cache.ReadCache; public class SharedStringsTableHandler extends DefaultHandler { private static final String T_TAG = "t"; private static final String SI_TAG = "si"; + /** + * Mac 2016 2017 will have this extra field to ignore + */ + private static final String RPH_TAG = "rPh"; + /** * The final piece of data */ @@ -23,6 +28,14 @@ public class SharedStringsTableHandler extends DefaultHandler { private StringBuilder currentElementData; private ReadCache readCache; + /** + * Some fields in the T tag need to be ignored + */ + private boolean ignoreTagt = false; + /** + * The only time you need to read the characters in the T tag is when it is used + */ + private boolean isTagt = false; public SharedStringsTableHandler(ReadCache readCache) { this.readCache = readCache; @@ -32,8 +45,11 @@ public class SharedStringsTableHandler extends DefaultHandler { public void startElement(String uri, String localName, String name, Attributes attributes) { if (T_TAG.equals(name)) { currentElementData = null; + isTagt = true; } else if (SI_TAG.equals(name)) { currentData = null; + } else if (RPH_TAG.equals(name)) { + ignoreTagt = true; } } @@ -46,17 +62,23 @@ public class SharedStringsTableHandler extends DefaultHandler { } currentData.append(currentElementData); } + isTagt = false; } else if (SI_TAG.equals(name)) { if (currentData == null) { readCache.put(null); } else { readCache.put(currentData.toString()); } + } else if (RPH_TAG.equals(name)) { + ignoreTagt = false; } } @Override public void characters(char[] ch, int start, int length) { + if (!isTagt || ignoreTagt) { + return; + } if (currentElementData == null) { currentElementData = new StringBuilder(); } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java index 9b77c8c2..815ef06e 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java @@ -101,6 +101,12 @@ public class ReadWorkbookHolder extends AbstractReadHolder { */ private POIFSFileSystem poifsFileSystem; + /** + * Excel 2003 cannot read specific sheet. It can only read sheet by sheet.So when you specify one sheet, you ignore + * the others. + */ + private Boolean ignoreRecord03; + public ReadWorkbookHolder(ReadWorkbook readWorkbook) { super(readWorkbook, null, readWorkbook.getConvertAllFiled()); this.readWorkbook = readWorkbook; @@ -144,6 +150,7 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.defaultReturnMap = readWorkbook.getDefaultReturnMap(); } this.hasReadSheet = new HashSet(); + this.ignoreRecord03 = Boolean.FALSE; } public ReadWorkbook getReadWorkbook() { @@ -258,6 +265,14 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.poifsFileSystem = poifsFileSystem; } + public Boolean getIgnoreRecord03() { + return ignoreRecord03; + } + + public void setIgnoreRecord03(Boolean ignoreRecord03) { + this.ignoreRecord03 = ignoreRecord03; + } + @Override public HolderEnum holderType() { return HolderEnum.WORKBOOK; diff --git a/src/main/java/com/alibaba/excel/util/BooleanUtils.java b/src/main/java/com/alibaba/excel/util/BooleanUtils.java index c09506ba..55c48a18 100644 --- a/src/main/java/com/alibaba/excel/util/BooleanUtils.java +++ b/src/main/java/com/alibaba/excel/util/BooleanUtils.java @@ -8,7 +8,6 @@ package com.alibaba.excel.util; public class BooleanUtils { private static final String TRUE_NUMBER = "1"; - private static final String FALSE_NUMBER = "0"; private BooleanUtils() {} diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java index e619e370..c03c8434 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java @@ -174,7 +174,8 @@ public class ExcelBuilderImpl implements ExcelBuilder { if (cellIndex != 0) { cellIndex++; } - for (int i = 0; i < oneRowData.size() - dataIndex; i++) { + int size = oneRowData.size() - dataIndex; + for (int i = 0; i < size; i++) { doAddBasicTypeToExcel(oneRowData, null, row, relativeRowIndex, dataIndex++, cellIndex++); } } @@ -184,7 +185,8 @@ public class ExcelBuilderImpl implements ExcelBuilder { beforeCellCreate(row, head, relativeRowIndex); Cell cell = WorkBookUtil.createCell(row, cellIndex); Object value = oneRowData.get(dataIndex); - CellData cellData = converterAndSet(context.currentWriteHolder(), value.getClass(), cell, value, null); + CellData cellData = + converterAndSet(context.currentWriteHolder(), value == null ? null : value.getClass(), cell, value, null); afterCellCreate(head, cellData, cell, relativeRowIndex); } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiFormatTest.java index 99885fa9..1f31f9cc 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiFormatTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiFormatTest.java @@ -28,7 +28,7 @@ public class PoiFormatTest { @Test public void lastRowNum() throws IOException { - String file = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + String file = "D:\\test\\原文件.xlsx"; SXSSFWorkbook xssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(file)); SXSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0); LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgTest.java index 17e22de6..62e5b154 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgTest.java @@ -23,8 +23,8 @@ public class HgTest { @Test public void hh() throws IOException { - List list = EasyExcel.read(new FileInputStream("D:\\test\\hg2.xlsx")).autoTrim(Boolean.FALSE).sheet() - .headRowNumber(0).doReadSync(); + List list = + EasyExcel.read(new FileInputStream("D:\\test\\原文件.xlsx")).headRowNumber(0).sheet().doReadSync(); for (Object data : list) { LOGGER.info("返回数据:{}", JSON.toJSONString(data)); } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/RepeatListener.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/RepeatListener.java new file mode 100644 index 00000000..aa54b396 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/RepeatListener.java @@ -0,0 +1,51 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.demo.read.DemoDataListener; +import com.alibaba.easyexcel.test.temp.LockData; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +public class RepeatListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + @Override + public void invoke(LockData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/RepeatTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/RepeatTest.java new file mode 100644 index 00000000..517220e5 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/RepeatTest.java @@ -0,0 +1,58 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.temp.LockData; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.fastjson.JSON; + +/** + * 测试poi + * + * @author Jiaju Zhuang + **/ +@Ignore +public class RepeatTest { + private static final Logger LOGGER = LoggerFactory.getLogger(RepeatTest.class); + + @Test + public void hh() throws IOException { + ExcelReader reader = + EasyExcel.read(new FileInputStream("D:\\test\\hg2.xls"), LockData.class, new RepeatListener()) + .headRowNumber(0).build(); + ReadSheet r1 = EasyExcel.readSheet(0).build(); + ReadSheet r2 = EasyExcel.readSheet(2).build(); + reader.read(r1); + reader.read(r2); + reader.finish(); + } + + @Test + public void hh2() throws IOException { + ExcelReader reader = + EasyExcel.read(new FileInputStream("D:\\test\\sheet.xls"), LockData.class, new RepeatListener()) + .headRowNumber(0).build(); + ReadSheet r2 = EasyExcel.readSheet(1).build(); + reader.read(r2); + reader.finish(); + } + + @Test + public void hh1() throws IOException { + ExcelReader reader = + EasyExcel.read(new FileInputStream("D:\\test\\hg2.xls"), LockData.class, new RepeatListener()) + .headRowNumber(0).build(); + ReadSheet r2 = EasyExcel.readSheet(0).build(); + reader.read(r2); + reader.finish(); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java new file mode 100644 index 00000000..62b64b57 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java @@ -0,0 +1,51 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.demo.write.DemoData; +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.fastjson.JSON; + +/** + * 测试poi + * + * @author Jiaju Zhuang + **/ +@Ignore +public class Wirte { + private static final Logger LOGGER = LoggerFactory.getLogger(Wirte.class); + + @Test + public void simpleWrite() { + // 写法1 + String fileName = TestFileUtil.getPath() + "ttttttttt11" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 如果这里想使用03 则 传入excelType参数即可 + EasyExcel.write(fileName).sheet("模板").doWrite(data()); + } + + private List> data() { + List> list = new ArrayList>(); + for (int i = 0; i < 10; i++) { + List list1 = new ArrayList(); + + list1.add("字符串" + i); + list1.add(new Date()); + list1.add(0.56); + list.add(list1); + } + return list; + } +} diff --git a/update.md b/update.md index e9e7d5e5..88df3f9c 100644 --- a/update.md +++ b/update.md @@ -1,3 +1,8 @@ +# 2.0.0-beta4 +* 修改在传入List>判断行数错误 [Issue #526](https://github.com/alibaba/easyexcel/issues/526) +* 修复在mac 2016 2017导出的excel 可能存在多余字段的问题 +* 修复03版 读取无法指定sheet的问题 [Issue #533](https://github.com/alibaba/easyexcel/issues/533) + # 2.0.0-beta3 * 导出完成移除临时目录 [Issue #386](https://github.com/alibaba/easyexcel/issues/386) * 新增读取返回头数据