zoukankan      html  css  js  c++  java
  • POI实现excel大数据量导入

    依据了https://blog.csdn.net/u013488171/article/details/78184545的帖子,感谢作者小逝的无私分享。

    本人亲测导入4万条数据用时32分钟,因为有我自己本人项目的数据校验,大家的时间很可能不一样。

    备注:我应用的时候出了这样的错误,最后没用这个方法,我的另一个帖子:https://www.cnblogs.com/daguozb/p/10043986.html,解析路径错误。

    用到的jar包;

    bios-poi-ooxml-3.9.jar

    导入的思路见原博客,我说下我应用的文件建立思路:建立一个作为工具类的:抽象类BigDataParseExcelUtil,在抽象类中实现了excel的转换(转换过程可以不看);对外展现接口process(String filename)来传入文件路径,并有个抽象方法对外迭代输出excel每行数据。

    然后在你的方法里用匿名内部类的形式使用,实现抽象方法optRows,完成自己的操作。

    代码如下:

    抽象类BigDataParseExcelUtil

    package com.iss.itms.util.excel;
    
    import java.io.InputStream;
    import java.sql.SQLException;
    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.GregorianCalendar;
    import java.util.Iterator;
    import java.util.List;
    
    import org.apache.commons.lang.StringUtils;
    import org.apache.commons.lang.time.DateUtils;
    import org.apache.poi3.openxml4j.opc.OPCPackage;
    import org.apache.poi3.xssf.eventusermodel.XSSFReader;
    import org.apache.poi3.xssf.model.SharedStringsTable;
    import org.apache.poi3.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 com.toft.utils.ToftLogger;
    
    /**
     * XSSF and SAX (Event API)
     */
    public abstract class BigDataParseExcelUtil 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; // 当前列索引
        private int preCol = 0; // 上一列列索引
        private int titleRow = 0; // 标题行,一般情况下为0
        private int rowsize = 0; // 列数
        private List excelList=new ArrayList();  //excel全部转换为list
    
        // excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型
    
        public abstract void optRows(int sheetIndex, int curRow,
                List<String> rowlist,List excelList) throws SQLException, Exception;
    
        // 只遍历一个sheet,其中sheetId为要遍历的sheet索引,从1开始,1-3
        /**
         * 
         * @param filename
         * @param sheetId
         *            sheetId为要遍历的sheet索引,从1开始,1-3
         * @throws Exception
         */
        public void processOneSheet(String filename, int sheetId) throws Exception {
            OPCPackage pkg = OPCPackage.open(filename);
            XSSFReader r = new XSSFReader(pkg);
            SharedStringsTable sst = r.getSharedStringsTable();
            XMLReader parser = fetchSheetParser(sst);
            // rId2 found by processing the Workbook
            // 根据 rId# 或 rSheet# 查找sheet
            InputStream sheet2 = r.getSheet("rId" + sheetId);
            sheetIndex++;
            InputSource sheetSource = new InputSource(sheet2);
            parser.parse(sheetSource);
            sheet2.close();
        }
    
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            // 得到单元格内容的值
            lastContents += new String(ch, start, length);
        }
    
        /**
         * 遍历 excel 文件
         */
        public void process(String filename) throws Exception {
    //        String fileString="C:\Users\hp\Desktop\新建\model_ebankcertificate.xlsx";
            ToftLogger.info("---process(String filename)方法的filename值为:"+filename);
            OPCPackage pkg = OPCPackage.open(filename);
            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();
            }
        }
    
        public XMLReader fetchSheetParser(SharedStringsTable sst)
                throws SAXException {
            XMLReader parser = XMLReaderFactory.createXMLReader();
            // .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) throws SAXException {
            // c => 单元格
            if (name.equals("c")) {
                // 如果下一个元素是 SST 的索引,则将nextIsString标记为true
                String cellType = attributes.getValue("t");
                String rowStr = attributes.getValue("r");
                curCol = this.getRowIndex(rowStr);
                if (cellType != null && cellType.equals("s")) {
                    nextIsString = true;
                } else {
                    nextIsString = false;
                }
            }
            // 置空
            lastContents = "";
        }
    
        public void endElement(String uri, String localName, String name)
                throws SAXException {
            // 根据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;
                int cols = curCol - preCol;
                if (cols > 1) {
                    for (int i = 0; i < cols - 1; i++) {
                        rowlist.add(preCol, "");
                    }
                }
                preCol = curCol;
                rowlist.add(curCol - 1, value);
            } else {
                // 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法
                if (name.equals("row")) {
                    int tmpCols = rowlist.size();
                    if (curRow > this.titleRow && tmpCols < this.rowsize) {
                        for (int i = 0; i < this.rowsize - tmpCols; i++) {
                            rowlist.add(rowlist.size(), "");
                        }
                    }
                    try {
                        optRows(sheetIndex, curRow, rowlist,excelList);
                    } catch (SQLException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    if (curRow == this.titleRow) {
                        this.rowsize = rowlist.size();
                    }
                    rowlist.clear();
                    curRow++;
                    curCol = 0;
                    preCol = 0;
                }
            }
        }
    
        // 得到列索引,每一列c元素的r属性构成为字母加数字的形式,字母组合为列索引,数字组合为行索引,
        // 如AB45,表示为第(A-A+1)*26+(B-A+1)*26列,45行
        public int getRowIndex(String rowStr) {
            rowStr = rowStr.replaceAll("[^A-Z]", "");
            byte[] rowAbc = rowStr.getBytes();
            int len = rowAbc.length;
            float num = 0;
            for (int i = 0; i < len; i++) {
                num += (rowAbc[i] - 'A' + 1) * Math.pow(26, len - i - 1);
            }
            return (int) num;
        }
        
        public  void text(int t){
            Calendar c = new GregorianCalendar(1900,0,0);
            Date d = c.getTime();
            Date _d = DateUtils.addDays(d, t);
            System.out.println(_d.toLocaleString());
            }
    
        public List getExcelList() {
            return this.excelList;
        }
    
        // 测试使用
        public static void main(String[] args) throws Exception {
            long start = System.currentTimeMillis();
            BigDataParseExcelUtil xlx = new BigDataParseExcelUtil() {
                @Override
                public void optRows(int sheetIndex, int curRow, List<String> rowlist,List excelList)
                        throws SQLException {
                    System.out.println(rowlist);
                    if(!"证书到期日*".equals(rowlist.get(6))){
                        int parseInt = Integer.parseInt(rowlist.get(6));
                        System.out.println(parseInt);
                        text(parseInt-1);    
                    }
    
                }
            };
            // xlx.process("C:\Users\winitadmin\导出123.xlsx");
            xlx.process("C:\Users\hp\Desktop\model_ebankcertificatedfs.xlsx");
            long end = System.currentTimeMillis();
            System.out.println((end - start) / 1000);
        }
    }

    我对BigDataParseExcelUtil的应用,上面代码只是实现了excel的解析和转换,我们要把解析好的数据插入到数据库,完成操作。

        public void impdata() throws Exception{
            //匿名内部类,实现工具类的操作方法,完成导入功能
            BigDataParseExcelUtil xlx = new BigDataParseExcelUtil() {
                List<String> onlyUCode=new ArrayList<String>();//记录导入文件的Code,避免重复
                @Override
                public void optRows(int sheetIndex, int curRow, List<String> rowlist,List excelList) throws Exception
                {
                    ToftLogger.info("---进入方法optRows-----");
                    //excelList,onlyUCode是我自己项目用的,你们自决定去留。去掉的话在工具类里也改下
                    impdataOperation(sheetIndex,curRow,rowlist,excelList,onlyUCode);
                }
            };
            String fileName = this.getContext().getAttribute("fileName").toString();
            xlx.process(fileName);
            List excelList = xlx.getExcelList();//我在impdataOperation方法里把excle的数据全部放到了excelList里,所以这里能get到
            
    
        }

    上面impdataOperation方法是我完成自己项目实现的方法,不贴了;一般就是校验个列数据。

    注意:1、什么时候知道excel导入完成?

    我也不知道,所以我就在我上面加了excelList属性,在impdataOperation方法中校验完成就给excelList添加一条,知道最后一条,到List excelList = xlx.getExcelList();就获得了全部的数据。大家有好的方法希望留言。

    先这样,有问题大家多评论。

  • 相关阅读:
    取随机数
    端口号
    cut命令
    渗透
    ssh免密登陆
    漏洞扫描
    信息收集1:DNSEUM命令
    Centos6与Centos7的区别
    HAPROXY+KEEPALIVED实现负载均衡
    this的用法
  • 原文地址:https://www.cnblogs.com/daguozb/p/10031970.html
Copyright © 2011-2022 走看看