POI大数量读取excel文件

来源:互联网 发布:去外企工作好吗 知乎 编辑:程序博客网 时间:2024/06/18 00:35

         最近在处理大数据量excel导入的问题,在java中我们导入excel通常使用的是apache的通用包POI。

         首先按照POI通用的方法导入的时候报出了内存溢出,后来在apache官网中找到了event api这个方法,event api这个方法是直接根据xml读取excel的,内存占用量很少,效率高, 但是使用起来比较麻烦,首先要开启要读取的文件,还要建立xml的reader。通过reader来读取excel文件的内容,这个event api只适用于xlsx类型文件。具体代码如下:

        public void readExcelToCollection(File file,SheetContentsHandler sheetContentsHandler) throws IOException, SAXException, OpenXML4JException, ParserConfigurationException {
OPCPackage pkg = OPCPackage.open(file, PackageAccess.READ);
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(pkg);
                XSSFReader xssfReader = new XSSFReader(pkg);
                StylesTable styles = xssfReader.getStylesTable();
                Iterator<InputStream> sheetItor = xssfReader.getSheetsData();
                while(sheetItor.hasNext()) {
             InputStream is = sheetItor.next();
             InputSource source = new InputSource(is);
             XMLReader sheetParser = SAXHelper.newXMLReader();
                    ContentHandler handler = new XSSFSheetXMLHandler(styles, strings, sheetContentsHandler, true); 
                    sheetParser.setContentHandler(handler);
                    sheetParser.parse(source);
                }
}

这里最重要的方法是sheetContentsHandler,这个方法是继承的一个poi提供的接口SheetContentsHandler接口,它提供了读取行、单元格的接口,我们继承之后可以直接在类中操作读取excel的内容。

      private class MyMapSheetHandler extends MySheetHandler{

private Map<String,Object> resultMap;


@Override
public void readCell(String formattedValue) {
resultMap.put(excelFieldMap.get(this.fieldNameMap.get(this.currentCellNum)), formattedValue);
}

@Override
public void endRow(int rowNum) {
if(rowNum < endRowNum) {
excelResultMapList.add(resultMap); //赋值
}
}


@Override
public void readRow(int rowNum) {
resultMap = new HashMap<String,Object>();

}

private abstract class MySheetHandler implements SheetContentsHandler {


protected Integer currentRowNum = 0;  //当前行数

protected Integer currentCellNum = 0; //当前cell数


protected Map<Integer,String> fieldNameMap = new LinkedHashMap<Integer,String>();  //存储excel中读取的标头


@Override
public void startRow(int rowNum) {
currentCellNum = 0;
currentRowNum = rowNum;
if(currentRowNum > firstRowNum) {
readRow(rowNum);
}
}

@Override
public void cell(String cellReference, String formattedValue,
XSSFComment comment) {
if(firstRowNum == currentRowNum) {
fieldNameMap.put(currentCellNum,formattedValue); //赋值title值
} else {
readCell(formattedValue);
}

currentCellNum++;
}


@Override
public void headerFooter(String text, boolean isHeader, String tagName) {

}

public abstract void readCell(String formattedValue);

public abstract void readRow(int rowNum);
}

        具体个性化的操作都可以字节jichengprivate class MyMapSheetHandler extends MySheetHandler{

private Map<String,Object> resultMap;


@Override
public void readCell(String formattedValue) {
resultMap.put(excelFieldMap.get(this.fieldNameMap.get(this.currentCellNum)), formattedValue);
}

@Override
public void endRow(int rowNum) {
if(rowNum < endRowNum) {
excelResultMapList.add(resultMap); //赋值
}
}


@Override
public void readRow(int rowNum) {
resultMap = new HashMap<String,Object>();

}

private abstract class MySheetHandler implements SheetContentsHandler {


protected Integer currentRowNum = 0;  //当前行数

protected Integer currentCellNum = 0; //当前cell数


protected Map<Integer,String> fieldNameMap = new LinkedHashMap<Integer,String>();  //存储excel中读取的标头


@Override
public void startRow(int rowNum) {
currentCellNum = 0;
currentRowNum = rowNum;
if(currentRowNum > firstRowNum) {
readRow(rowNum);
}
}

@Override
public void cell(String cellReference, String formattedValue,
XSSFComment comment) {
if(firstRowNum == currentRowNum) {
fieldNameMap.put(currentCellNum,formattedValue); //赋值title值
} else {
readCell(formattedValue);
}

currentCellNum++;
}


@Override
public void headerFooter(String text, boolean isHeader, String tagName) {

}

public abstract void readCell(String formattedValue);

public abstract void readRow(int rowNum);
}   


       这里是我自己的实现方法,具体的实现可以根据自己的业务逻辑来读取,这里只是 简单的从excel中读取内容并保存到map中。

       参考资料:https://poi.apache.org/spreadsheet/how-to.html