JAVA解析Excel工具easyexcel之深入源代碼解密原理

    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();
                }
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章