JAVA解析Excel工具easyexcel之深入源代码解密原理
程序员文章站
2024-01-08 13:06:16
...
EasyExcel.read(file, HeadReadData.class, new HDListener()).sheet(0).doRead();
EasyExcel.read(file, HeadReadData.class, new HDListener())将文件、表头类、读监听器传进去,创建ExcelReaderBuilder并将三个参数保存到ExcelReaderBuilder中的一个属性ReadWorkbook中。
public static ExcelReaderBuilder read(File file, Class head, ReadListener readListener) {
//创建excel读构建器
ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
//分别传入file、head、readListener
excelReaderBuilder.file(file);
if (head != null) {
excelReaderBuilder.head(head);
}
if (readListener != null) {
excelReaderBuilder.registerReadListener(readListener);
}
return excelReaderBuilder;
}
public class ExcelReaderBuilder {
/**
* Workbook
*/
private ReadWorkbook readWorkbook;
public ExcelReaderBuilder() {
this.readWorkbook = new ReadWorkbook();
}
ReadWorkbook extends ReadBasicParameter
EasyExcel.read(file, HeadReadData.class, new HDListener()).sheet(0).doRead();
public ExcelReaderSheetBuilder sheet(Integer sheetNo) {
return sheet(sheetNo, null);
}
sheet(0)返回 excelReaderSheetBuilder构建器
public ExcelReaderSheetBuilder sheet(Integer sheetNo, String sheetName) {
ExcelReaderSheetBuilder excelReaderSheetBuilder = new ExcelReaderSheetBuilder(build());
if (sheetNo != null) {
excelReaderSheetBuilder.sheetNo(sheetNo);
}
if (sheetName != null) {
excelReaderSheetBuilder.sheetName(sheetName);
}
return excelReaderSheetBuilder;
}
而build()就是利用文件、表头类、读监听器返回一个ExcelReader,readWorkbook中保存了文件、表头类、读监听器。
public ExcelReader build() {
return new ExcelReader(readWorkbook);
}
ExcelReader
public ExcelReader(ReadWorkbook readWorkbook) {
excelAnalyser = new ExcelAnalyserImpl(readWorkbook);
}
ExcelAnalyserImpl
public ExcelAnalyserImpl(ReadWorkbook readWorkbook) {
try {
analysisContext = new AnalysisContextImpl(readWorkbook);
choiceExcelExecutor();
} catch (RuntimeException e) {
finish();
throw e;
} catch (Throwable e) {
finish();
throw new ExcelAnalysisException(e);
}
}
//选择不同的excel执行器,XLS、XLSX
private void choiceExcelExecutor() throws Exception {
ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
ExcelTypeEnum excelType = readWorkbookHolder.getExcelType();
if (excelType == null) {
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null);
return;
}
switch (excelType) {
case XLS:
**//POIFSFileSystem poi的文件读取api
POIFSFileSystem poifsFileSystem;**
if (readWorkbookHolder.getFile() != null) {
poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getFile());
} else {
poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getInputStream());
}
// So in encrypted excel, it looks like XLS but it's actually XLSX
if (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
InputStream decryptedStream = null;
try {
decryptedStream =
DocumentFactoryHelper.getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(),
analysisContext.readWorkbookHolder().getPassword());
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream);
return;
} finally {
IOUtils.closeQuietly(decryptedStream);
// as we processed the full stream already, we can close the filesystem here
// otherwise file handles are leaked
poifsFileSystem.close();
}
}
if (analysisContext.readWorkbookHolder().getPassword() != null) {
Biff8EncryptionKey.setCurrentUserPassword(analysisContext.readWorkbookHolder().getPassword());
}
excelReadExecutor = new XlsSaxAnalyser(analysisContext, poifsFileSystem);
break;
case XLSX:
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null);
break;
default:
}
}
AnalysisContextImpl
public AnalysisContextImpl(ReadWorkbook readWorkbook) {
if (readWorkbook == null) {
throw new IllegalArgumentException("Workbook argument cannot be null");
}
readWorkbookHolder = new ReadWorkbookHolder(readWorkbook);
currentReadHolder = readWorkbookHolder;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Initialization 'AnalysisContextImpl' complete");
}
}
ReadWorkbookHolder开始读取readWorkbook中传进来的属性。
public ReadWorkbookHolder(ReadWorkbook readWorkbook) {
super(readWorkbook, null, readWorkbook.getConvertAllFiled());
this.readWorkbook = readWorkbook;
if (readWorkbook.getInputStream() != null) {
if (readWorkbook.getInputStream().markSupported()) {
this.inputStream = readWorkbook.getInputStream();
} else {
this.inputStream = new BufferedInputStream(readWorkbook.getInputStream());
}
}
this.file = readWorkbook.getFile();
if (file == null && inputStream == null) {
throw new ExcelAnalysisException("File and inputStream must be a non-null.");
}
if (readWorkbook.getMandatoryUseInputStream() == null) {
this.mandatoryUseInputStream = Boolean.FALSE;
} else {
this.mandatoryUseInputStream = readWorkbook.getMandatoryUseInputStream();
}
if (readWorkbook.getAutoCloseStream() == null) {
this.autoCloseStream = Boolean.TRUE;
} else {
this.autoCloseStream = readWorkbook.getAutoCloseStream();
}
// The type of excel is read according to the judgment.Because encrypted XLSX needs to be specified as XLS to
// properly parse.
this.excelType = ExcelTypeEnum.valueOf(file, inputStream, readWorkbook.getExcelType());
if (ExcelTypeEnum.XLS == excelType && getGlobalConfiguration().getUse1904windowing() == null) {
getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
}
this.customObject = readWorkbook.getCustomObject();
if (readWorkbook.getIgnoreEmptyRow() == null) {
this.ignoreEmptyRow = Boolean.TRUE;
} else {
this.ignoreEmptyRow = readWorkbook.getIgnoreEmptyRow();
}
if (readWorkbook.getReadCache() != null) {
if (readWorkbook.getReadCacheSelector() != null) {
throw new ExcelAnalysisException("'readCache' and 'readCacheSelector' only one choice.");
}
this.readCacheSelector = new EternalReadCacheSelector(readWorkbook.getReadCache());
} else {
if (readWorkbook.getReadCacheSelector() == null) {
this.readCacheSelector = new SimpleReadCacheSelector();
} else {
this.readCacheSelector = readWorkbook.getReadCacheSelector();
}
}
if (readWorkbook.getDefaultReturnMap() == null) {
this.defaultReturnMap = Boolean.TRUE;
} else {
this.defaultReturnMap = readWorkbook.getDefaultReturnMap();
}
this.xlsxSAXParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName();
this.hasReadSheet = new HashSet<Integer>();
this.ignoreRecord03 = Boolean.FALSE;
this.password = readWorkbook.getPassword();
}
以上便是初始化创建环境,下面开始读取文档内容:
EasyExcel.read(file, HeadReadData.class, new HDListener()).sheet(0)**.doRead();**
public void doRead() {
if (excelReader == null) {
throw new ExcelGenerateException("Must use 'EasyExcelFactory.read().sheet()' to call this method");
}
excelReader.read(build());
excelReader.finish();
}
public ReadSheet build() {
//在前面环境构建的时候设置了readSheet对象,关于sheet的序号,名称
return readSheet;
}
调用excelReader的read
public ExcelReader read(ReadSheet... readSheet) {
return read(Arrays.asList(readSheet));
}
public ExcelReader read(List<ReadSheet> readSheetList) {
excelAnalyser.analysis(readSheetList, Boolean.FALSE);
return this;
}
核心读取步骤:
@Override
public void analysis(List<ReadSheet> readSheetList, Boolean readAll) {
try {
if (!readAll && CollectionUtils.isEmpty(readSheetList)) {
throw new IllegalArgumentException("Specify at least one read sheet.");
}
try {
//根据创建环境时选择的excelReadExecutor进行读取
excelReadExecutor.execute(readSheetList, readAll);
} catch (ExcelAnalysisStopException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Custom stop!");
}
}
// The last sheet is read
if (excelReadExecutor instanceof XlsSaxAnalyser) {
if (analysisContext.readSheetHolder() != null) {
analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);
}
}
} catch (RuntimeException e) {
finish();
throw e;
} catch (Throwable e) {
finish();
throw new ExcelAnalysisException(e);
}
}
两个excelReadExecutor
@Override
public void execute(List<ReadSheet> readSheetList, Boolean readAll) {
for (ReadSheet readSheet : sheetList) {
readSheet = SheetUtils.match(readSheet, readSheetList, readAll,
analysisContext.readWorkbookHolder().getGlobalConfiguration());
if (readSheet != null) {
analysisContext.currentSheet(readSheet);
parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(analysisContext, stylesTable));
// The last sheet is read
analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);
}
}
}
private void parseXmlSource(InputStream inputStream, ContentHandler handler) {
InputSource inputSource = new InputSource(inputStream);
try {
SAXParserFactory saxFactory;
String xlsxSAXParserFactoryName = analysisContext.readWorkbookHolder().getXlsxSAXParserFactoryName();
if (StringUtils.isEmpty(xlsxSAXParserFactoryName)) {
saxFactory = SAXParserFactory.newInstance();
} else {
saxFactory = SAXParserFactory.newInstance(xlsxSAXParserFactoryName, null);
}
saxFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
saxFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser saxParser = saxFactory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setContentHandler(handler);
xmlReader.parse(inputSource);
inputStream.close();
} catch (ExcelAnalysisException e) {
throw e;
} catch (Exception e) {
throw new ExcelAnalysisException(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
throw new ExcelAnalysisException("Can not close 'inputStream'!");
}
}
}
监听器的调用:
public void notifyEndOneRow(AnalysisFinishEvent event, AnalysisContext analysisContext) {
Map<Integer, CellData> cellDataMap = event.getAnalysisResult();
if (CollectionUtils.isEmpty(cellDataMap)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.warn("Empty row!");
}
if (analysisContext.readWorkbookHolder().getIgnoreEmptyRow()) {
return;
}
}
ReadRowHolder readRowHolder = analysisContext.readRowHolder();
readRowHolder.setCurrentRowAnalysisResult(cellDataMap);
int rowIndex = readRowHolder.getRowIndex();
int currentheadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber();
if (rowIndex >= currentheadRowNumber) {
// Now is data
for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {
try {
**readListener.invoke(readRowHolder.getCurrentRowAnalysisResult(), analysisContext);**
} catch (Exception e) {
for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) {
try {
readListenerException.onException(e, analysisContext);
} catch (Exception exception) {
throw new ExcelAnalysisException(exception.getMessage(), exception);
}
}
break;
}
if (!readListener.hasNext(analysisContext)) {
throw new ExcelAnalysisStopException();
}
}
} else {
// Last head column
if (currentheadRowNumber == rowIndex + 1) {
buildHead(analysisContext, cellDataMap);
}
// Now is header
for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {
try {
readListener.invokeHead(cellDataMap, analysisContext);
} catch (Exception e) {
for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) {
try {
readListenerException.onException(e, analysisContext);
} catch (Exception exception) {
throw new ExcelAnalysisException(exception.getMessage(), exception);
}
}
break;
}
if (!readListener.hasNext(analysisContext)) {
throw new ExcelAnalysisStopException();
}
}
}
}