java读取excel大文件

在读取excel大文件的时候就不能再使用poi包下面的Workbook类,会造成OOM等问题。
我们常见的excel分为xlsx格式和csv格式。分别实现一下。

xlsx格式处理。

  1. 需要的pom依赖:
		<dependency>
			<groupId>xercesgroupId>
			<artifactId>xercesImplartifactId>
			<version>2.9.0version>
		dependency>
		<dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poiartifactId>
            <version>4.1.2version>
        dependency>
        
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poi-ooxmlartifactId>
            <version>4.1.2version>
        dependency>

java代码如下

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @program: automan-admin
 * @description: 该类的主要是作用逐行解析xlsx文件,适合大文件操作
 * @author: xpb
 * @date: 2020-12-17 14:14
 **/
public abstract class ExcelUtil<E> extends DefaultHandler {

    private SharedStringsTable sst;
    private String lastContents;
    private boolean nextIsString;

    private int sheetIndex = -1;
    private List<String> rowlist = new ArrayList<String>();
    private int curRow = 0;
    private int curCol = 0;
    //该字段用于你解析后需要的关联处理,不需要则传null
    private E object;


    /**
     * 读取第一个工作簿的入口方法
     * @param path
     */
    public void readOneSheet(String path, E e) throws Exception {
        this.object = e;
        //该处读取的是远程存储的url,如果是本地文件,可以使用下面的语句
        OPCPackage pkg = OPCPackage.open(new URL(path).openStream());
        //OPCPackage pkg = OPCPackage.open(path);
        XSSFReader r = new XSSFReader(pkg);
        SharedStringsTable sst = r.getSharedStringsTable();

        XMLReader parser = fetchSheetParser(sst);

        InputStream sheet = r.getSheet("rId1");

        InputSource sheetSource = new InputSource(sheet);
        parser.parse(sheetSource);

        sheet.close();
    }


    /**
     * 读取所有工作簿的入口方法
     * @param path
     * @throws Exception
     */
    public void process(String path) throws Exception {
        OPCPackage pkg = OPCPackage.open(path);
        XSSFReader r = new XSSFReader(pkg);
        SharedStringsTable sst = r.getSharedStringsTable();

        XMLReader parser = fetchSheetParser(sst);

        Iterator<InputStream> sheets = r.getSheetsData();
        while (sheets.hasNext()) {
            curRow = 0;
            sheetIndex++;
            InputStream sheet = sheets.next();
            InputSource sheetSource = new InputSource(sheet);
            parser.parse(sheetSource);
            sheet.close();
        }
    }

    /**
     * 该方法自动被调用,每读一行调用一次,在方法中写自己的业务逻辑即可
     * 使用的时候重写该方法。
     * @param sheetIndex 工作簿序号
     * @param curRow 处理到第几行
     * @param rowList 当前数据行的数据集合
     */
    public abstract void optRow(int sheetIndex, int curRow, List<String> rowList, E e);


    public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException, SAXException {
        XMLReader parser =  XMLReaderFactory
                .createXMLReader("org.apache.xerces.parsers.SAXParser");
        this.sst = sst;
        parser.setContentHandler(this);
        return parser;
    }

    public void startElement(String uri, String localName, String name,
                             Attributes attributes){
        // c => 单元格
        if (name.equals("c")) {
            // 如果下一个元素是 SST 的索引,则将nextIsString标记为true
            String cellType = attributes.getValue("t");
            if (cellType != null && cellType.equals("s")) {
                nextIsString = true;
            } else {
                nextIsString = false;
            }
        }
        // 置空
        lastContents = "";
    }


    public void endElement(String uri, String localName, String name) {
        // 根据SST的索引值的到单元格的真正要存储的字符串
        // 这时characters()方法可能会被调用多次
        if (nextIsString) {
            try {
                int idx = Integer.parseInt(lastContents);
                lastContents = new XSSFRichTextString(sst.getEntryAt(idx))
                        .toString();
            } catch (Exception e) {

            }
        }

        // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引
        // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
        if (name.equals("v")) {
            String value = lastContents.trim();
            value = value.equals("") ? " " : value;
            rowlist.add(curCol, value);
            curCol++;
        } else {
            // 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法
            if (name.equals("row")) {
                optRow(sheetIndex, curRow, rowlist, object);
                rowlist.clear();
                curRow++;
                curCol = 0;
            }
        }
    }

    public void characters(char[] ch, int start, int length)
            throws SAXException {
        // 得到单元格内容的值
        lastContents += new String(ch, start, length);
    }
}

如何使用上面的工具类

/**
 * @program: mock-demo
 * @description: .
 * @author: xpb
 * @date: 2020-12-21 20:41
 **/
public class TestExcelUtil extends ExcelUtil<String>{

    @Override
    public void optRow(int sheetIndex, int curRow, List<String> rowList, String s) {
        //逐行处理读取的数据
    }
}

使用:

/**
 * @program: mock-demo
 * @description: ..
 * @author: xupengbo
 * @date: 2020-12-21 20:43
 **/
public class HandleTest {

    public static void main(String[] args) throws Exception {
        TestExcelUtil testExcelUtil = new TestExcelUtil();
        testExcelUtil.readOneSheet("", "aaaa");
    }
}

csv文件处理

public static void main(String[] args) throws Exception {
        //这是读取远程文件
        BufferedReader reader = new BufferedReader(new InputStreamReader(new URL("远程连接").openStream()));
        
        //reader.readLine();//第一行信息,为标题信息,不用,如果需要,注释掉
        String line = null;
        while ((line = reader.readLine()) != null) {
            String item[] = line.split(",");//CSV格式文件为逗号分隔符文件,这里根据逗号切分
            //如果单元格内存在逗号,需要自行处理一下。

        }
    }

你可能感兴趣的:(工具类,大excel,poi)