POI导入导出

导读:本篇文章讲解 POI导入导出,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1. POI介绍

在项目中经常做Excel的导入导出,Excel导入到处常用的工具就是POI和easyExcel,本文先来介绍POI,下一篇文章介绍EasyExcel。

1.1 POI

官网:https://poi.apache.org/
请添加图片描述
请添加图片描述
这主要介绍Excel相关的功能

1.2 Excel概念

  • 工作簿

    一张excel文件就是一个工作簿

  • 工作表

    excel中的一个sheet就是一个工作表

  • sheet中的一行就是一个单元行

  • 单元格

    一行中的一个列就是一个单元格

1.3 POI中的对象介绍

  • 工作簿

    使用WorkBook对象进行操作,实现类主要有HSSFWorkBook、XSSFWorkBook、SXSSFWorkBook

  • 工作表

    使用Sheet对象操作工作表,一个excel中有多个sheet

  • 使用Row对象操作工作表中的一行

  • 单元格

    使用Cell对象操作一行中的某一列

2. POI操作

文章对应源码地址: https://gitee.com/he_linhai/spring-boot-csdn/tree/master/02-poi-easyExcel

pom.xml

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>

2.1 POI Excel写

03 xls 写

/**
 * xls写
 *  使用 HSSFWorkbook 进行操作
 */
@Test
public void poi03Write() {
    // 工作簿
    try(Workbook workbook = new HSSFWorkbook();
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03simple.xls")) {
        // 工作表
        Sheet sheet1 = workbook.createSheet("sheet1");
        // 行
        Row row1 = sheet1.createRow(0);
        // 列
        Cell cell11 = row1.createCell(0);
        Cell cell12 = row1.createCell(1);
        // 1-1 1-2
        cell11.setCellValue("1-1");
        cell12.setCellValue("1-2");

        Row row2 = sheet1.createRow(1);
        Cell cell21 = row2.createCell(0);
        Cell cell22 = row2.createCell(1);
        // 2-1 2-2
        cell21.setCellValue("2-1");
        cell22.setCellValue("2-2");

        // 写出文件
        workbook.write(fileOutputStream);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • 结果
    请添加图片描述

07 xlsx 写

  • XSSFWorkBook
/**
 * xlsx 写
 *  使用 XSSFWorkbook 进行操作
 */
@Test
public void poi07Write() {
    // 工作簿
    try(Workbook workbook = new XSSFWorkbook();
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07simple.xlsx")) {
        // 工作表
        Sheet sheet1 = workbook.createSheet("sheet1");
        // 行
        Row row1 = sheet1.createRow(0);
        // 列
        Cell cell11 = row1.createCell(0);
        Cell cell12 = row1.createCell(1);
        // 1-1 1-2
        cell11.setCellValue("1-1");
        cell12.setCellValue("1-2");

        Row row2 = sheet1.createRow(1);
        Cell cell21 = row2.createCell(0);
        Cell cell22 = row2.createCell(1);
        // 2-1 2-2
        cell21.setCellValue("2-1");
        cell22.setCellValue("2-2");

        // 写出文件
        workbook.write(fileOutputStream);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • SXSSFWrokBook
/**
 * xlsx 写
 *  使用 SXSSFWorkbook 进行操作(优化之后的)
 */
@Test
public void poi07WriteSXSSF() {
    // 工作簿
    try(Workbook workbook = new SXSSFWorkbook();
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07simple.xlsx")) {
        // 工作表
        Sheet sheet1 = workbook.createSheet("sheet1");
        // 行
        Row row1 = sheet1.createRow(0);
        // 列
        Cell cell11 = row1.createCell(0);
        Cell cell12 = row1.createCell(1);
        // 1-1 1-2
        cell11.setCellValue("1-1");
        cell12.setCellValue("1-2");

        Row row2 = sheet1.createRow(1);
        Cell cell21 = row2.createCell(0);
        Cell cell22 = row2.createCell(1);
        // 2-1 2-2
        cell21.setCellValue("2-1");
        cell22.setCellValue("2-2");

        // 写出文件
        workbook.write(fileOutputStream);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • 结果
    请添加图片描述

2.2 POI Excel 读

03 xls 读

/**
 * xls读
 *  使用 HSSFWorkbook 进行操作
 */
@Test
public void poi03Read() {
    // 工作簿
    try(Workbook workbook = new HSSFWorkbook(new FileInputStream(PATH + "03simple.xls"))) {
        // 工作表
        Sheet sheet1 = workbook.getSheet("sheet1");
        // 行
        Row row1 = sheet1.getRow(0);
        // 列
        Cell cell11 = row1.getCell(0);
        Cell cell12 = row1.getCell(1);
        // 1-1 1-2
        System.out.println("1-1" + ": " + cell11.getStringCellValue());
        System.out.println("1-2" + ": " + cell12.getStringCellValue());

        Row row2 = sheet1.getRow(1);
        Cell cell21 = row2.getCell(0);
        Cell cell22 = row2.getCell(1);
        // 2-1 2-2
        System.out.println("2-1" + ": " + cell21.getStringCellValue());
        System.out.println("2-2" + ": " + cell22.getStringCellValue());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • 结果

请添加图片描述

07 xlsx 读

  • XSSFWorkbook
/**
 * xlsx 读
 *  使用 XSSFWorkbook 进行操作
 */
@Test
public void poi07Read() {
    // 工作簿
    try(Workbook workbook = new XSSFWorkbook(new FileInputStream(PATH + "07simple.xlsx"))) {
        // 工作表
        Sheet sheet1 = workbook.getSheet("sheet1");
        // 行
        Row row1 = sheet1.getRow(0);
        // 列
        Cell cell11 = row1.getCell(0);
        Cell cell12 = row1.getCell(1);
        // 1-1 1-2
        System.out.println("1-1" + ": " + cell11.getStringCellValue());
        System.out.println("1-2" + ": " + cell12.getStringCellValue());

        Row row2 = sheet1.getRow(1);
        Cell cell21 = row2.getCell(0);
        Cell cell22 = row2.getCell(1);
        // 2-1 2-2
        System.out.println("2-1" + ": " + cell21.getStringCellValue());
        System.out.println("2-2" + ": " + cell22.getStringCellValue());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • SXSSFWorkbook
/**
 * xlsx 读
 *  使用 SXSSFWorkbook 进行操作(优化之后的)
 */
@Test
public void poi07ReadSXSSF() {
    // 工作簿
    try(Workbook workbook = new XSSFWorkbook(new FileInputStream(PATH + "07simple.xlsx"))) {
        // 工作表
        Sheet sheet1 = workbook.getSheet("sheet1");
        // 行
        Row row1 = sheet1.getRow(0);
        // 列
        Cell cell11 = row1.getCell(0);
        Cell cell12 = row1.getCell(1);
        // 1-1 1-2
        System.out.println("1-1" + ": " + cell11.getStringCellValue());
        System.out.println("1-2" + ": " + cell12.getStringCellValue());

        Row row2 = sheet1.getRow(1);
        Cell cell21 = row2.getCell(0);
        Cell cell22 = row2.getCell(1);
        // 2-1 2-2
        System.out.println("2-1" + ": " + cell21.getStringCellValue());
        System.out.println("2-2" + ": " + cell22.getStringCellValue());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • 结果
    请添加图片描述

2.3 POI Cell多格式读取

org.apache.poi.ss.usermodel.CellType中规定了cell的几种数据类型

类型 描述
@Internal(since=“POI 3.15 beta 3”)
_NONE(-1)
未知类型,仅限内部使用
NUMERIC(0) 数值类型,小数,日期
STRING(1) 字符串
FORMULA(2) 公式
BLANK(3) 空单元个,没值,但是有单元格样式
BOOLEAN(4) 布尔值
ERROR(5) 错误单元格
/**
 * 解析列
 * @param cell 单元格
 * @param workbook 工作簿
 * @return 解析完的数据
 */
private Object getCellData(Cell cell, Workbook workbook) {
    Object result = null;

    CellType cellType = cell.getCellTypeEnum();
    switch (cellType) {
        case STRING:
            result = cell.getStringCellValue();
            break;
        case BOOLEAN:
            result = cell.getBooleanCellValue();
            break;
        case NUMERIC:
            if (DateUtil.isCellDateFormatted(cell)) {
                result = cell.getDateCellValue();
            } else {
                result = cell.getNumericCellValue();
            }
            break;
        case FORMULA:
            FormulaEvaluator formulaEvaluator = null;
            if (workbook instanceof HSSFWorkbook) {
                formulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);
            } else if (workbook instanceof XSSFWorkbook) {
                formulaEvaluator = new XSSFFormulaEvaluator((XSSFWorkbook) workbook);
            } else if (workbook instanceof SXSSFWorkbook) {
                formulaEvaluator = new SXSSFFormulaEvaluator((SXSSFWorkbook) workbook);
            }
            if (formulaEvaluator != null) {
                CellValue evaluate = formulaEvaluator.evaluate(cell);
                result = getCellData(evaluate, workbook);
            }
            break;
        default:
            break;
    }
    return result;
}


/**
 * 获取CellValue的值
 * @param cellValue CellValue
 * @param workbook 工作薄
 * @return 解析完的数据
 */
private Object getCellData(CellValue cellValue, Workbook workbook) {
    Object result = null;

    CellType cellType = cellValue.getCellTypeEnum();
    switch (cellType) {
        case STRING:
            result = cellValue.getStringValue();
            break;
        case BOOLEAN:
            result = cellValue.getBooleanValue();
            break;
        case NUMERIC:
            result = cellValue.getNumberValue();
            break;
        default:
            break;
    }
    return result;
}

2.4 POI Excel大数据量写

一下数据为JVM 8G内存的导出测试

03 xls 大数据量写

​ 03版本的xls后缀的文件,单sheet最多存储65536条数据,

​ 使用HSSFWorkBook对象写出即可

​ 单出单sheet最多数据,耗时2s,没有优化的必要

/**
 * xls大文件写
 *  使用 HSSFWorkbook 进行操作
 *  使用xls格式最多写入65536行数据  2.174s
 */
@Test
public void poi03Write() {
    // 工作簿
    try(Workbook workbook = new HSSFWorkbook();
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03big.xls")) {
        long start = System.currentTimeMillis();

        // 工作表
        Sheet sheet = workbook.createSheet();
        // 写 65536 条数据
        for (int i = 0; i < 65536; i++) {
            // 行
            Row row = sheet.createRow(i);
            for (int j = 0; j < 50; j++) {
                // 列
                Cell cell = row.createCell(j);
                cell.setCellValue(j);
            }
        }

        // 写出文件
        workbook.write(fileOutputStream);

        long end = System.currentTimeMillis();
        System.out.println(((double)end - start ) / 1000);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

07 xlsx 导出

​ 使用XSSFWorkBook进行操作

​ 以8g内存为例,25万条数据会报OOM

​ 实测20万可以,但是会占用大量内存,加上业务操作,很容易OOM,不推荐使用

/**
 * xlsx 写
 *  使用 XSSFWorkbook 进行操作
 *  写入 25万 条数据 java 最高8G 空间 25万条就会内存溢出OOM
 *      20万条测试可以 66.928s
 *  单sheet最多到处1048575行
 */
@Test
public void poi07Write() {
    // 工作簿
    try(Workbook workbook = new XSSFWorkbook();
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07big.xlsx")) {
        long start = System.currentTimeMillis();

        // 工作表
        Sheet sheet1 = workbook.createSheet();
        // 写 1000000 条数据
        for (int i = 0; i < 200000; i++) {
            // 行
            Row row = sheet1.createRow(i);
            for (int j = 0; j < 50; j++) {
                // 列
                Cell cell = row.createCell(j);
                cell.setCellValue(j);
            }
        }

        // 写出文件
        workbook.write(fileOutputStream);

        long end = System.currentTimeMillis();
        System.out.println(((double)end - start ) / 1000);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

POI 针对xlsx版本的excel导出进行优化,使用SXSSFWorkbook对象进行操作

会分批刷盘,减少内存使用量

原理

​ 其原理是可以定义一个window size(默认100),生成Excel期间只在内存维持window size那么多的行数Row,超时window size时会把之前行Row写到一个临时文件并且remove释放掉,这样就可以达到释放内存的效果。SXSSFSheet在创建Row时会判断并刷盘、释放超过window size的Row。

/**
 * xlsx 写
 *  使用 SXSSFWorkbook 进行操作(优化之后的)
 *  100万条数据,占用内存500多M,耗时43.288秒
 *  单sheet最多到处1048576行
 */
@Test
public void poi07WriteSXSSF() {
    /// 工作簿
    try(Workbook workbook = new SXSSFWorkbook();
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07big.xlsx")) {
        long start = System.currentTimeMillis();

        // 工作表
        Sheet sheet1 = workbook.createSheet();
        // 写 1000000 条数据
        for (int i = 0; i < 1000000; i++) {
            // 行
            Row row = sheet1.createRow(i);
            for (int j = 0; j < 50; j++) {
                // 列
                Cell cell = row.createCell(j);
                cell.setCellValue(j);
            }
        }

        // 写出文件
        workbook.write(fileOutputStream);

        long end = System.currentTimeMillis();
        System.out.println(((double)end - start ) / 1000);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2.5 POI Excel 大数据量读

03 xls 导入

​ 使用HSSFWorkBook导入,

​ 单sheet极限数据65536行数据,用时30s

/**
 * xls读
 * 使用 HSSFWorkbook 进行操作
 * 读取 65536行数据 占用内存 2G左右,用时 30.602s
 */
@Test
public void poi03Read() {
    long start = System.currentTimeMillis();

    List<List<Object>> list = new ArrayList<>();
    // 工作簿
    try (Workbook workbook = new HSSFWorkbook(new FileInputStream(PATH + "03big.xls"))) {
        // 工作表
        Sheet sheet1 = workbook.getSheetAt(0);
        int lastRowNum = sheet1.getLastRowNum();
        if (lastRowNum == 0) {
            return;
        }
        Iterator<Row> iterator = sheet1.iterator();
        while (iterator.hasNext()) {
            ArrayList<Object> rowData = new ArrayList<>();

            Row row = iterator.next();
            Iterator<Cell> cellIterator = row.cellIterator();
            while (cellIterator.hasNext()) {
                Cell cell = cellIterator.next();
                Object cellValue = getCellData(cell, workbook);
                rowData.add(cellValue);
            }
            list.add(rowData);
        }
        System.out.println(list);
    } catch (Exception e) {
        e.printStackTrace();
    }

    long end = System.currentTimeMillis();
    System.out.println();
    System.out.println(((double) end - start) / 1000);
}

07 xlsx 导入

​ 使用XSSFWorkbook操作

​ 读取30万数据,直接OOM,而且POI并没有为导入优化的SXSSFWorkBook

/**
 * xlsx 读
 * 使用 XSSFWorkbook 进行操作
 * 读取30万条数据,直接OOM
 */
@Test
public void poi07Read() {
    long start = System.currentTimeMillis();

    List<List<Object>> list = new ArrayList<>();
    // 工作簿
    try (Workbook workbook = new XSSFWorkbook(new FileInputStream(PATH + "07big.xlsx"))) {
        // 工作表
        Sheet sheet1 = workbook.getSheetAt(0);
        // 最后的行号 真实行号-1,标识下标
        int lastRowNum = sheet1.getLastRowNum();
        // 物理行数,真实行数
        // int physicalNumberOfRows = sheet1.getPhysicalNumberOfRows();
        if (lastRowNum == 0) {
            return;
        }
        for (int i = 0; i <= lastRowNum; i++) {
            ArrayList<Object> rowData = new ArrayList<>();

            Row row = sheet1.getRow(i);
            Iterator<Cell> cellIterator = row.cellIterator();
            while (cellIterator.hasNext()) {
                Cell cell = cellIterator.next();
                Object cellValue = getCellData(cell, workbook);
                rowData.add(cellValue);
            }
            list.add(rowData);
        }
        System.out.println(list);
    } catch (Exception e) {
        e.printStackTrace();
    }

    long end = System.currentTimeMillis();
    System.out.println();
    System.out.println(((double) end - start) / 1000);
}

2.6 导入优化

POI对导入分为3种模式,用户模式User Model,事件模式Event Model,还有Event User Model。

  • User Model(用户模式)就类似于DOM方式的解析,把文件一次性读入内存,构造一颗dom树。并且在POI对excel的抽象而知,每一行,每一个单元格都是一个对象。当文件大时,数据量多时,对内存的占用可想而知。如果文件太大,会导致OOM
  • Event Model(事件模式)就是SAX解析。Event Model使用的方式时边读取,边解析,并且不会将这些数据封装成Row,Cell这些对象。而都是普通的数字或者字符串。并且这些解析出来的对象,不需要一直驻留到内存中,而是解析完,使用后就可以回收。所以相对于User Model,更加节省内存,效率更高。但是相比User Model的功能更少,门槛更高。需要了解xml解析规则
  • Event User Model也是采用流式解析,但是不同于Event Model,POI基于EventModel为我们封装了一层。我们不再面对Element的事件编程,而是面相StartRow,EndRow,Cell等事件编程。而提供的数据,也不想之前是原始数据,而是全部格式化好的,方便开发者开箱急用。大大简化了我们的开发效率

XLSX

POI对XLSX支持Event Model和Event User Model,重点介绍EventUserModel模式的代码实现,因为简单易用。其他模式仅做介绍

XLSX的Event Model

使用

最直接,权威就是参考官网例子简单来说就是需要继承DefaultHandler,覆盖其startElement,endElement方法。然后方法里获取你想要的数据。

原理

DefaultHandler相信熟悉的人都知道,这是JDK自带的对XML的SAX解析用到处理类,POI在进行SAX解析时,把读取到每个XML的元素时则会回调这两个方法,然后我们就可以获取到想用的数据了。我们回忆一下上面说到的XLSX存储格式中sheet存储数据的格式。再看看官方例子中的解析过程

@Override
public void startElement(String uri, String localName, String name,
                            Attributes attributes) throws SAXException {
    //c代表是一个单元格cell,判断c这个xml元素里面属性attribute t
    // c => cell
    if(name.equals("c")) {
        // Print the cell reference
        System.out.print(attributes.getValue("r") + " - ");
        // Figure out if the value is an index in the SST
        String cellType = attributes.getValue("t");
        nextIsString = cellType != null && cellType.equals("s");
        inlineStr = cellType != null && cellType.equals("inlineStr");
    }
    // Clear contents cache
    lastContents = "";
}

@Override
public void endElement(String uri, String localName, String name)
        throws SAXException {
    // Process the last contents as required.
    // Do now, as characters() may be called more than once
    if(nextIsString) {
        Integer idx = Integer.valueOf(lastContents);
        lastContents = lruCache.get(idx);
        if (lastContents == null && !lruCache.containsKey(idx)) {
            lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
            lruCache.put(idx, lastContents);
        }
        nextIsString = false;
    }

    //v 元素代表这个cell的内容
    // v => contents of a cell
    // Output after we've seen the string contents
    if(name.equals("v") || (inlineStr && name.equals("c"))) {
        System.out.println(lastContents);
    }
}

可以看出你需要对XLSX的XML格式清楚,才能获取到你想要的东西。

XLSX的Event User Model

使用

官方例子简单来说就是继承XSSFSheetXMLHandler.SheetContentsHandler,覆盖其startRow,endRow,cell 等方法。POI每开始读行,结束读行,读取一个cell。从方法名上看Event User Model有更好的用户体验。

EventUserModelTest

public class EventUserModelTest {

    /**
     * EventUserModel模式可以支持大数据量导出
     *  100万数据
     *  每次处理1000条 耗时97.786s 内存1G左右
     *  每次处理10000条 耗时107.24s 内存1.3G左右
     */
    @Test
    public void test() {
        long start = System.currentTimeMillis();
        new ExcelEventUserModelParse("/media/hlh/13B69828E0E35204/A-IdeaProject-UOS/spring-boot-csdn/02-poi-easyExcel/src/file/07big.xlsx")
                .setHandler(new SimpleSheetContentsHandler(1000)).parse();
        long end = System.currentTimeMillis();
        System.out.println();
        System.out.println(((double) end - start) / 1000);
    }

}

ExcelEventUserModelParse

public class ExcelEventUserModelParse {

    /** 文件名称 */
    private final String filename;
    /** 分批处理的条数 */
    private int handlerNum = 1000;
    /** 解析类 */
    private XSSFSheetXMLHandler.SheetContentsHandler handler;

    public ExcelEventUserModelParse(String filename) {
        this.filename = filename;
    }

    public ExcelEventUserModelParse(String filename, int handlerNum) {
        this.filename = filename;
        this.handlerNum = handlerNum;
    }

    public ExcelEventUserModelParse setHandler(XSSFSheetXMLHandler.SheetContentsHandler handler) {
        this.handler = handler;
        return this;
    }

    /**
     * 统一解析入口
     */
    public void parse() {
        OPCPackage pkg = null;
        InputStream sheetInputStream = null;
        try {
            pkg = OPCPackage.open(filename, PackageAccess.READ);
            XSSFReader xssfReader = new XSSFReader(pkg);
            StylesTable styles = xssfReader.getStylesTable();
            ReadOnlySharedStringsTable readOnlySharedStringsTable = new ReadOnlySharedStringsTable(pkg);
            sheetInputStream = xssfReader.getSheetsData().next();
            processSheet(styles, readOnlySharedStringsTable, sheetInputStream);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            if (sheetInputStream != null) {
                try {
                    sheetInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (pkg != null) {
                try {
                    pkg.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     *
     * @param styles
     * @param strings
     * @param sheetInputStream
     * @throws SAXException
     * @throws ParserConfigurationException
     * @throws IOException
     */
    private void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, InputStream sheetInputStream)
            throws SAXException, ParserConfigurationException, IOException {
        XMLReader sheetParser = SAXHelper.newXMLReader();

        if (handler != null) {
            sheetParser.setContentHandler(new XSSFSheetXMLHandler(styles, strings, handler, false));
        } else {
            sheetParser.setContentHandler(
                    new XSSFSheetXMLHandler(styles, strings, new SimpleSheetContentsHandler(handlerNum), false));
        }

        sheetParser.parse(new InputSource(sheetInputStream));
    }

}

SimpleSheetContentsHandler

public class SimpleSheetContentsHandler implements XSSFSheetXMLHandler.SheetContentsHandler {

    /** 当前行 */
    int currRow = 0;
    /** 总记录 */
    List<List<String>> listData = new ArrayList<>();
    /** 单条临时记录 */
    List<String> rowData;
    /** 分批处理的条数 */
    private int handlerNum = 1000;

    public SimpleSheetContentsHandler(int handlerNum) {
        this.handlerNum = handlerNum;
    }

    /**
     * 开始一行的回调
     * @param rowNum 行号
     */
    @Override
    public void startRow(int rowNum) {
        // System.out.println("startRow: " + rowNum);
        rowData = new ArrayList<>();
    }

    /**
     * 结束一行的回调
     * @param rowNum 行号
     */
    @Override
    public void endRow(int rowNum) {
        // System.out.println("endRow: " + rowNum);
        // 将临时记录添加到总记录中
        listData.add(rowData);
        rowData = null;
        currRow++;
        // 如果到达指定处理数量,进行处理,清空总记录
        if (currRow % handlerNum == 0) {
            System.out.println(listData);
            listData.clear();
        }
    }

    /**
     * 当行处理完成的回调
     * @param cellReference 当前所在的单元个
     * @param formattedValue 格式化之后的字符串
     * @param comment 注释
     */
    @Override
    public void cell(String cellReference, String formattedValue, XSSFComment comment) {
        // 处理每一行中的每一列
        rowData.add(formattedValue);
    }

    @Override
    public void headerFooter(String text, boolean isHeader, String tagName) {
        System.out.println("headerFooter...");
        System.out.println(text);
        System.out.println(isHeader);
        System.out.println(tagName);
    }

}
原理

其实Event User Model也是 Event Model的封装,在XSSFSheetXMLHandler(其实也是一个DefaultHandler来的)中持有一个SheetContentsHandler,在其startElement,endElement方法中会调用SheetContentsHandler的startRow,endRow,cell等方法。

XLS

POI对XLS支持Event Model

使用

官网例子

需要继承HSSFListener,覆盖processRecord 方法,POI每读取到一个单元格的数据则会回调次方法。

原理

这里涉及BIFF8格式以及POI对其的封装,大家可以了解一下(因为其格式比较复杂,我也不是很清楚)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/68320.html

(0)
小半的头像小半

相关推荐

极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!