精华内容
下载资源
问答
  • poi读取大文件Excel

    千次阅读 2019-04-09 21:25:06
    背景 ...最后对照时间点,发现宕机的时候业务人员在上传一个excel文件,但是这个excel文件才28MB大小,感觉应该不会引起内存溢出。后来在本地启动了服务,然后尝试上传这个excel文件,同时使用Java...

    背景

    • 前一段时间遇到一种情况,服务器经常宕机,而且没有规律性,查看GC日志发生了out of memory,是堆溢出导致的,分析了一下堆的dump文件,发现在发生OOM时创建了大量的String对象。最后对照时间点,发现宕机的时候业务人员在上传一个excel文件,但是这个excel文件才28MB大小,感觉应该不会引起内存溢出。后来在本地启动了服务,然后尝试上传这个excel文件,同时使用Java VisualVM监控GC情况,发现在上传的时候,创建了大量的String对象,后来老年代没有可分配空间导致了OOM。最终分析结果是,excel文件中存在几十万的空行数据,表面上看,这些空行数据跟不存在数据的行是一样的,但是POI会把这种空行数据读入到内存中,感觉这也是一个坑。
    • 在网上搜了很长时间,发现国内网站上的解决方案真是没法看,基本上答案都差不多,没有什么有见解性的解决方法,后来在stackoverflow上找到了解决方法。算是给自己做一下备注,也想帮助一些还在坑里的人,就分享一下,只是自己的见解,有不得当的地方也请见谅。
    • 原先获取方法
      /**
         * 获取execle 文件
         *
         * @param fileName
         * @return
         */
        public  static Workbook getWookBook(String fileName) {
            Workbook workbook = null;
            FileInputStream fileInputStream = null;
            try {
                File file = new File(fileName);
                if (!file.exists()) {
                    System.out.println("模板文件:" + fileName + "不存在!");
                }
                fileInputStream = new FileInputStream(fileName);
                workbook = WorkbookFactory.create(fileInputStream);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InvalidFormatException e) {
                e.printStackTrace();
            } finally {
                CloseableUtils.close(fileInputStream);
            }
            return workbook;
        }
    
    • 使用Excel Streaming Reader,这个第三方工具会把一部分的行(可以设置)缓存到内存中,在迭代时不断加载行到内存中,而不是一次性的加载所有记录到内存,这样就可以不断的读取excel内容并且不影响内存的使用。

    • 但是这个工具也有一定的限制:只能用于读取excel的内容,写入操作不可用;可以使用getSheetAt()方法获取到对应的Sheet,因为当前只是加载了有限的row在内存中,因此不能随机访问row,即不能使用getRow(int rowNum)方法;由于行数据已经加载到了内存,因此可以随机的访问Cell数据,即可以使用getCell(int cellnum)方法。使用这个工具,建议使用迭代器来进行迭代。具体内容可以参见:https://github.com/monitorjbl/excel-streaming-reader。
      在pom.xml文件中引入需要的jar包:

      	<dependency>
               <groupId>com.monitorjbl</groupId>
               <artifactId>xlsx-streamer</artifactId>
               <version>1.2.0</version>
           </dependency>
    
    
    @Test
        public void testLoad() throws Exception{
            FileInputStream in = new FileInputStream("e:/2.xlsx");
            Workbook wk = StreamingReader.builder()
                    .rowCacheSize(100)  //缓存到内存中的行数,默认是10
                    .bufferSize(4096)  //读取资源时,缓存到内存的字节大小,默认是1024
                    .open(in);  //打开资源,必须,可以是InputStream或者是File,注意:只能打开XLSX格式的文件
            Sheet sheet = wk.getSheetAt(0);
            //遍历所有的行
            for (Row row : sheet) {
                System.out.println("开始遍历第" + row.getRowNum() + "行数据:");
                //遍历所有的列
                for (Cell cell : row) {
                    System.out.print(cell.getStringCellValue() + " ");
                }
                System.out.println(" ");
            }
        }
    
    • 最终写法
     /**
         * 获取execle 文件
         *
         * @param fileName
         * @return
         */
        public static Workbook getWookBook(String fileName) {
            Workbook workbook = null;
            if (VerifyUtil.isEmpty(fileName)) return workbook;
            boolean b = fileName.endsWith(".xlsx");
            if (b) {
                return getXlsx(fileName);
            }
            FileInputStream fileInputStream = null;
            try {
                File file = new File(fileName);
                if (!file.exists()) {
                    System.out.println("模板文件:" + fileName + "不存在!");
                }
                fileInputStream = new FileInputStream(fileName);
                workbook = WorkbookFactory.create(fileInputStream);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InvalidFormatException e) {
                e.printStackTrace();
            } finally {
                CloseableUtils.close(fileInputStream);
            }
            return workbook;
        }
    
        /**
         * @return
         * @throws
         * @Description 解析xlsx 大文件类型
         * @author liuding
         * @date 2019/4/10 0010 08:57
         */
        public static Workbook getXlsx(String fileName) {
            FileInputStream in = null;
            try {
                System.out.println("文件:" + fileName);
                in = new FileInputStream(fileName);
                System.out.println("文件大小:" + String.valueOf(in.available()) + "--" + in.available() / 1024 / 1024);
                Workbook workbook = StreamingReader.builder()
                        .rowCacheSize(100)  //缓存到内存中的行数,默认是10
                        .bufferSize(4096)  //读取资源时,缓存到内存的字节大小,默认是1024
                        .open(in);  //打开资源,必须,可以是InputStream或者是File,注意:只能打开XLSX格式的文件
                return workbook;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    展开全文
  • 使用POI读取大文件Excel

    千次阅读 2019-01-23 13:14:01
    前言:前段时间,由于项目中有一个功能,导入大量的数据,整个Excel的容量大概有200M左右,用以前的方法读取很慢,甚至会内存溢出,所以后面改用另外一种方式(驱动模式),其实我也不是很懂,是借鉴了一个前辈的...

    前言:前段时间,由于项目中有一个功能,导入大量的数据,整个Excel的容量大概有200M左右,用以前的方法读取很慢,甚至会内存溢出,所以后面改用另外一种方式(驱动模式),其实我也不是很懂,是借鉴了一个前辈的思路(https://www.cnblogs.com/swordfall/p/8298386.html),下面直接上码

     

    1.引入jar包,POI的依赖包

    <!-- poi office -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>3.16</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>3.16</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml-schemas</artifactId>
                <version>3.16</version>
            </dependency>

    2.解析Excel2003的类ExcelXlsReader

    public class ExcelXlsReader implements HSSFListener {
    
        private int minColums = -1;
    
        private POIFSFileSystem fs;
    
        /**
         * 总行数
         */
        private int totalRows=0;
    
        /**
         * 上一行row的序号
         */
        private int lastRowNumber;
    
        /**
         * 上一单元格的序号
         */
        private int lastColumnNumber;
    
        /**
         * 是否输出formula,还是它对应的值
         */
        private boolean outputFormulaValues = true;
    
        /**
         * 用于转换formulas
         */
        private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
    
        //excel2003工作簿
        private HSSFWorkbook stubWorkbook;
    
        private SSTRecord sstRecord;
    
        private FormatTrackingHSSFListener formatListener;
    
        private final HSSFDataFormatter formatter = new HSSFDataFormatter();
    
        /**
         * 文件的绝对路径
         */
        private String filePath = "";
    
        //表索引
        private int sheetIndex = 0;
    
        private BoundSheetRecord[] orderedBSRs;
    
        @SuppressWarnings("unchecked")
        private ArrayList boundSheetRecords = new ArrayList();
    
        private int nextRow;
    
        private int nextColumn;
    
        private boolean outputNextStringRecord;
    
        //当前行
        private int curRow = 0;
    
        //存储一行记录所有单元格的容器
        private List<String> cellList = new ArrayList<String>();
    
        //第一个sheet列表
        private static List<List<String>> firstSheetList = new ArrayList<>();
        //第二个sheet列表
        private static List<List<String>> secondSheetList = new ArrayList<>();
        //第三个sheet列表
        private static List<List<String>> thirdSheetList = new ArrayList<>();
    
        private static Map<String,List<List<String>>> allListMap = new HashMap<>();
    
    
        /**
         * 判断整行是否为空行的标记
         */
        private boolean flag = false;
    
        @SuppressWarnings("unused")
        private String sheetName;
    
        /**
         * 遍历excel下所有的sheet
         *
         * @param file
         * @throws Exception
         */
        public Map<String,List<List<String>>> process(File file) throws Exception {
    //        filePath = fileName;
            this.fs = new POIFSFileSystem(new FileInputStream(file));
            MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
            formatListener = new FormatTrackingHSSFListener(listener);
            HSSFEventFactory factory = new HSSFEventFactory();
            HSSFRequest request = new HSSFRequest();
            if (outputFormulaValues) {
                request.addListenerForAllRecords(formatListener);
            } else {
                workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
                request.addListenerForAllRecords(workbookBuildingListener);
            }
            factory.processWorkbookEvents(request, fs);
    
            allListMap.put("first",new ArrayList<>(firstSheetList));
            allListMap.put("second",new ArrayList<>(secondSheetList));
            allListMap.put("third",new ArrayList<>(thirdSheetList));
            firstSheetList.clear();
            secondSheetList.clear();
            thirdSheetList.clear();
            return allListMap;
        }
    
        /**
         * HSSFListener 监听方法,处理Record
         * 处理每个单元格
         * @param record
         */
        @SuppressWarnings("unchecked")
        public void processRecord(Record record) {
            int thisRow = -1;
            int thisColumn = -1;
            String thisStr = null;
            String value = null;
            switch (record.getSid()) {
                case BoundSheetRecord.sid:
                    boundSheetRecords.add(record);
                    break;
                case BOFRecord.sid: //开始处理每个sheet
                    BOFRecord br = (BOFRecord) record;
                    if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
                        //如果有需要,则建立子工作簿
                        if (workbookBuildingListener != null && stubWorkbook == null) {
                            stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
                        }
    
                        if (orderedBSRs == null) {
                            orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
                        }
                        sheetName = orderedBSRs[sheetIndex].getSheetname();
                        sheetIndex++;
                    }
                    break;
                case SSTRecord.sid:
                    sstRecord = (SSTRecord) record;
                    break;
                case BlankRecord.sid: //单元格为空白
                    BlankRecord brec = (BlankRecord) record;
                    thisRow = brec.getRow();
                    thisColumn = brec.getColumn();
                    thisStr = "";
                    cellList.add(thisColumn, thisStr);
                    break;
                case BoolErrRecord.sid: //单元格为布尔类型
                    BoolErrRecord berec = (BoolErrRecord) record;
                    thisRow = berec.getRow();
                    thisColumn = berec.getColumn();
                    thisStr = berec.getBooleanValue() + "";
                    cellList.add(thisColumn, thisStr);
                    checkRowIsNull(thisStr);  //如果里面某个单元格含有值,则标识该行不为空行
                    break;
                case FormulaRecord.sid://单元格为公式类型
                    FormulaRecord frec = (FormulaRecord) record;
                    thisRow = frec.getRow();
                    thisColumn = frec.getColumn();
                    if (outputFormulaValues) {
                        if (Double.isNaN(frec.getValue())) {
                            outputNextStringRecord = true;
                            nextRow = frec.getRow();
                            nextColumn = frec.getColumn();
                        } else {
                            thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';
                        }
                    } else {
                        thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';
                    }
                    cellList.add(thisColumn, thisStr);
                    checkRowIsNull(thisStr);  //如果里面某个单元格含有值,则标识该行不为空行
                    break;
                case StringRecord.sid: //单元格中公式的字符串
                    if (outputNextStringRecord) {
                        StringRecord srec = (StringRecord) record;
                        thisStr = srec.getString();
                        thisRow = nextRow;
                        thisColumn = nextColumn;
                        outputNextStringRecord = false;
                    }
                    break;
                case LabelRecord.sid:
                    LabelRecord lrec = (LabelRecord) record;
                    curRow = thisRow = lrec.getRow();
                    thisColumn = lrec.getColumn();
                    value = lrec.getValue().trim();
                    value = value.equals("") ? "" : value;
                    cellList.add(thisColumn, value);
                    checkRowIsNull(value);  //如果里面某个单元格含有值,则标识该行不为空行
                    break;
                case LabelSSTRecord.sid: //单元格为字符串类型
                    LabelSSTRecord lsrec = (LabelSSTRecord) record;
                    curRow = thisRow = lsrec.getRow();
                    thisColumn = lsrec.getColumn();
                    if (sstRecord == null) {
                        cellList.add(thisColumn, "");
                    } else {
                        value = sstRecord.getString(lsrec.getSSTIndex()).toString().trim();
                        value = value.equals("") ? "" : value;
                        cellList.add(thisColumn, value);
                        checkRowIsNull(value);  //如果里面某个单元格含有值,则标识该行不为空行
                    }
                    break;
                case NumberRecord.sid: //单元格为数字类型
                    NumberRecord numrec = (NumberRecord) record;
                    curRow = thisRow = numrec.getRow();
                    thisColumn = numrec.getColumn();
    
                    //第一种方式
                    //value = formatListener.formatNumberDateCell(numrec).trim();//这个被写死,采用的m/d/yy h:mm格式,不符合要求
    
                    //第二种方式,参照formatNumberDateCell里面的实现方法编写
                    Double valueDouble=((NumberRecord)numrec).getValue();
                    String formatString=formatListener.getFormatString(numrec);
                    if (formatString.contains("m/d/yy")){
                        formatString="yyyy-MM-dd hh:mm:ss";
                    }
                    int formatIndex=formatListener.getFormatIndex(numrec);
                    value=formatter.formatRawCellContents(valueDouble, formatIndex, formatString).trim();
    
                    value = value.equals("") ? "" : value;
                    //向容器加入列值
                    cellList.add(thisColumn, value);
                    checkRowIsNull(value);  //如果里面某个单元格含有值,则标识该行不为空行
                    break;
                default:
                    break;
            }
    
            //遇到新行的操作
            if (thisRow != -1 && thisRow != lastRowNumber) {
                lastColumnNumber = -1;
            }
    
            //空值的操作
            if (record instanceof MissingCellDummyRecord) {
                MissingCellDummyRecord mc = (MissingCellDummyRecord) record;
                curRow = thisRow = mc.getRow();
                thisColumn = mc.getColumn();
                cellList.add(thisColumn, "");
            }
    
            //更新行和列的值
            if (thisRow > -1)
                lastRowNumber = thisRow;
            if (thisColumn > -1)
                lastColumnNumber = thisColumn;
    
            //行结束时的操作
            if (record instanceof LastCellOfRowDummyRecord) {
                if (minColums > 0) {
                    //列值重新置空
                    if (lastColumnNumber == -1) {
                        lastColumnNumber = 0;
                    }
                }
                lastColumnNumber = -1;
    
                if (flag&&curRow!=0) { //该行不为空行且该行不是第一行,发送(第一行为列名,不需要)
                    switch(sheetIndex){
                        case 1 :
                            //第一个sheet
                            List<String> a = new ArrayList<>(cellList);
                            firstSheetList.add(a);
                            break;
                        case 2 :
                            //第二个sheet
                            List<String> b = new ArrayList<>(cellList);
                            secondSheetList.add(b);
                            break;
                        case 3 :
                            //第三个sheet
                            List<String> c =  new ArrayList<>(cellList);
                            thirdSheetList.add(c);
                            break;
                        default :
                            break;
                    }
                    totalRows++;
                }
                //清空容器
                cellList.clear();
                flag=false;
            }
        }
    
        /**
         * 如果里面某个单元格含有值,则标识该行不为空行
         * @param value
         */
        public void checkRowIsNull(String value){
            if (value != null && !"".equals(value)) {
                flag = true;
            }
        }
    
    }
    

    3.解析Excel2007的类ExcelXlsxReader

    public class ExcelXlsxReader extends DefaultHandler {
    
    
        /**
         * 单元格中的数据可能的数据类型
         */
        enum CellDataType {
            BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER, DATE, NULL
        }
    
        /**
         * 共享字符串表
         */
        private SharedStringsTable sst;
    
        /**
         * 上一次的索引值
         */
        private String lastIndex;
    
        /**
         * 文件的绝对路径
         */
        private String filePath = "";
    
        /**
         * 工作表索引
         */
        private int sheetIndex = 0;
    
        /**
         * sheet名
         */
        private String sheetName = "";
    
        /**
         * 总行数
         */
        private int totalRows=0;
    
        /**
         * 一行内cell集合
         */
        private static List<String> cellList = new ArrayList<>();
    
        //第一个sheet列表
        private static List<List<String>> firstSheetList = new ArrayList<>();
        //第二个sheet列表
        private static List<List<String>> secondSheetList = new ArrayList<>();
        //第三个sheet列表
        private static List<List<String>> thirdSheetList = new ArrayList<>();
    
        private static Map<String,List<List<String>>> allListMap = new HashMap<>();
    
        /**
         * 判断整行是否为空行的标记
         */
        private boolean flag = false;
    
        /**
         * 当前行
         */
        private int curRow = 1;
    
        /**
         * 当前列
         */
        private int curCol = 0;
    
        /**
         * T元素标识
         */
        private boolean isTElement;
    
        /**
         * 异常信息,如果为空则表示没有异常
         */
        private String exceptionMessage;
    
        /**
         * 单元格数据类型,默认为字符串类型
         */
        private CellDataType nextDataType = CellDataType.SSTINDEX;
    
        private final DataFormatter formatter = new DataFormatter();
    
        /**
         * 单元格日期格式的索引
         */
        private short formatIndex;
    
        /**
         * 日期格式字符串
         */
        private String formatString;
    
        //定义前一个元素和当前元素的位置,用来计算其中空的单元格数量,如A6和A8等
        private String preRef = null, ref = null;
    
        //定义该文档一行最大的单元格数,用来补全一行最后可能缺失的单元格
        private String maxRef = null;
    
        /**
         * 单元格
         */
        private StylesTable stylesTable;
    
        /**
         * 遍历工作簿中所有的电子表格
         * 并缓存在mySheetList中
         *
         * @param file
         * @throws Exception
         */
        public Map<String,List<List<String>>> process(File file) throws Exception {
    //        filePath = filename;
            OPCPackage pkg = OPCPackage.open(file);
            XSSFReader xssfReader = new XSSFReader(pkg);
            stylesTable = xssfReader.getStylesTable();
            SharedStringsTable sst = xssfReader.getSharedStringsTable();
            XMLReader parser = XMLReaderFactory.createXMLReader("com.sun.org.apache.xerces.internal.parsers.SAXParser");
            this.sst = sst;
            parser.setContentHandler(this);
            XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
            while (sheets.hasNext()) { //遍历sheet
                curRow = 1; //标记初始行为第一行
                sheetIndex++;
                InputStream sheet = sheets.next(); //sheets.next()和sheets.getSheetName()不能换位置,否则sheetName报错
                sheetName = sheets.getSheetName();
                InputSource sheetSource = new InputSource(sheet);
                parser.parse(sheetSource); //解析excel的每条记录,在这个过程中startElement()、characters()、endElement()这三个函数会依次执行
                sheet.close();
            }
            allListMap.put("first",new ArrayList<>(firstSheetList));
            allListMap.put("second",new ArrayList<>(secondSheetList));
            allListMap.put("third",new ArrayList<>(thirdSheetList));
            firstSheetList.clear();
            secondSheetList.clear();
            thirdSheetList.clear();
            return allListMap; //返回该excel文件的总行数,不包括首列和空行
        }
    
        /**
         * 第一个执行
         *
         * @param uri
         * @param localName
         * @param name
         * @param attributes
         * @throws SAXException
         */
        @Override
        public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
            //c => 单元格
            if ("c".equals(name)) {
                //前一个单元格的位置
                if (preRef == null) {
                    preRef = attributes.getValue("r");
                } else {
                    preRef = ref;
                }
    
                //当前单元格的位置
                ref = attributes.getValue("r");
                //设定单元格类型
                this.setNextDataType(attributes);
            }
    
            //当元素为t时
            if ("t".equals(name)) {
                isTElement = true;
            } else {
                isTElement = false;
            }
    
            //置空
            lastIndex = "";
        }
    
        /**
         * 第二个执行
         * 得到单元格对应的索引值或是内容值
         * 如果单元格类型是字符串、INLINESTR、数字、日期,lastIndex则是索引值
         * 如果单元格类型是布尔值、错误、公式,lastIndex则是内容值
         * @param ch
         * @param start
         * @param length
         * @throws SAXException
         */
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            lastIndex += new String(ch, start, length);
        }
    
        /**
         * 第三个执行
         *
         * @param uri
         * @param localName
         * @param name
         * @throws SAXException
         */
        @Override
        public void endElement(String uri, String localName, String name) throws SAXException {
    
            //t元素也包含字符串
            if (isTElement) {//这个程序没经过
                //将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
                String value = lastIndex.trim();
                cellList.add(curCol, value);
                curCol++;
                isTElement = false;
                //如果里面某个单元格含有值,则标识该行不为空行
                if (value != null && !"".equals(value)) {
                    flag = true;
                }
            } else if ("v".equals(name)) {
                //v => 单元格的值,如果单元格是字符串,则v标签的值为该字符串在SST中的索引
                String value = this.getDataValue(lastIndex.trim(), "");//根据索引值获取对应的单元格值
                //补全单元格之间的空单元格
                if (!ref.equals(preRef)) {
                    int len = countNullCell(ref, preRef);
                    for (int i = 0; i < len; i++) {
                        cellList.add(curCol, "");
                        curCol++;
                    }
                }
                cellList.add(curCol, value);
                curCol++;
                //如果里面某个单元格含有值,则标识该行不为空行
                if (value != null && !"".equals(value)) {
                    flag = true;
                }
            } else {
                //如果标签名称为row,这说明已到行尾,调用optRows()方法
                if ("row".equals(name)) {
                    //默认第一行为表头,以该行单元格数目为最大数目
                    if (curRow == 1) {
                        maxRef = ref;
                    }
                    //补全一行尾部可能缺失的单元格
                    if (maxRef != null) {
                        int len = countNullCell(maxRef, ref);
                        for (int i = 0; i <= len; i++) {
                            cellList.add(curCol, "");
                            curCol++;
                        }
                    }
    
                    if (flag&&curRow!=1){ //该行不为空行且该行不是第一行,则发送(第一行为列名,不需要)
                        switch(sheetIndex){
                            case 1 :
                                //第一个sheet
                                List<String> a = new ArrayList<>(cellList);
                                firstSheetList.add(a);
                                break;
                            case 2 :
                                //第二个sheet
                                List<String> b = new ArrayList<>(cellList);
                                secondSheetList.add(b);
                                break;
                            case 3 :
                                //第三个sheet
                                List<String> c =  new ArrayList<>(cellList);
                                thirdSheetList.add(c);
                                break;
                            default :
                                break;
                        }
    //                    ExcelReaderUtil.sendRows(filePath, sheetName, sheetIndex, curRow, cellList);
                        totalRows++;
                    }
    
                    cellList.clear();
                    curRow++;
                    curCol = 0;
                    preRef = null;
                    ref = null;
                    flag=false;
                }
            }
        }
    
        /**
         * 处理数据类型
         *
         * @param attributes
         */
        public void setNextDataType(Attributes attributes) {
            nextDataType = CellDataType.NUMBER; //cellType为空,则表示该单元格类型为数字
            formatIndex = -1;
            formatString = null;
            String cellType = attributes.getValue("t"); //单元格类型
            String cellStyleStr = attributes.getValue("s"); //
            String columnData = attributes.getValue("r"); //获取单元格的位置,如A1,B1
    
            if ("b".equals(cellType)) { //处理布尔值
                nextDataType = CellDataType.BOOL;
            } else if ("e".equals(cellType)) {  //处理错误
                nextDataType = CellDataType.ERROR;
            } else if ("inlineStr".equals(cellType)) {
                nextDataType = CellDataType.INLINESTR;
            } else if ("s".equals(cellType)) { //处理字符串
                nextDataType = CellDataType.SSTINDEX;
            } else if ("str".equals(cellType)) {
                nextDataType = CellDataType.FORMULA;
            }
    
            if (cellStyleStr != null) { //处理日期
                int styleIndex = Integer.parseInt(cellStyleStr);
                XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
                formatIndex = style.getDataFormat();
                formatString = style.getDataFormatString();
    
                if (formatString.contains("m/d/yy")) {
                    nextDataType = CellDataType.DATE;
                    formatString = "yyyy-MM-dd hh:mm:ss";
                }
    
                if (formatString == null) {
                    nextDataType = CellDataType.NULL;
                    formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
                }
            }
        }
    
        /**
         * 对解析出来的数据进行类型处理
         * @param value   单元格的值,
         *                value代表解析:BOOL的为0或1, ERROR的为内容值,FORMULA的为内容值,INLINESTR的为索引值需转换为内容值,
         *                SSTINDEX的为索引值需转换为内容值, NUMBER为内容值,DATE为内容值
         * @param thisStr 一个空字符串
         * @return
         */
        @SuppressWarnings("deprecation")
        public String getDataValue(String value, String thisStr) {
            switch (nextDataType) {
                // 这几个的顺序不能随便交换,交换了很可能会导致数据错误
                case BOOL: //布尔值
                    char first = value.charAt(0);
                    thisStr = first == '0' ? "FALSE" : "TRUE";
                    break;
                case ERROR: //错误
                    thisStr = "\"ERROR:" + value.toString() + '"';
                    break;
                case FORMULA: //公式
                    thisStr = '"' + value.toString() + '"';
                    break;
                case INLINESTR:
                    XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
                    thisStr = rtsi.toString();
                    rtsi = null;
                    break;
                case SSTINDEX: //字符串
                    String sstIndex = value.toString();
                    try {
                        int idx = Integer.parseInt(sstIndex);
                        XSSFRichTextString rtss = new XSSFRichTextString(sst.getEntryAt(idx));//根据idx索引值获取内容值
                        thisStr = rtss.toString();
                        rtss = null;
                    } catch (NumberFormatException ex) {
                        thisStr = value.toString();
                    }
                    break;
                case NUMBER: //数字
                    if (formatString != null) {
                        thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString).trim();
                    } else {
                        thisStr = value;
                    }
                    thisStr = thisStr.replace("_", "").trim();
                    break;
                case DATE: //日期
                    thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString);
                    // 对日期字符串作特殊处理,去掉T
                    thisStr = thisStr.replace("T", " ");
                    break;
                default:
                    thisStr = " ";
                    break;
            }
            return thisStr;
        }
    
        public int countNullCell(String ref, String preRef) {
            //excel2007最大行数是1048576,最大列数是16384,最后一列列名是XFD
            String xfd = ref.replaceAll("\\d+", "");
            String xfd_1 = preRef.replaceAll("\\d+", "");
    
            xfd = fillChar(xfd, 3, '@', true);
            xfd_1 = fillChar(xfd_1, 3, '@', true);
    
            char[] letter = xfd.toCharArray();
            char[] letter_1 = xfd_1.toCharArray();
            int res = (letter[0] - letter_1[0]) * 26 * 26 + (letter[1] - letter_1[1]) * 26 + (letter[2] - letter_1[2]);
            return res - 1;
        }
    
        public String fillChar(String str, int len, char let, boolean isPre) {
            int len_1 = str.length();
            if (len_1 < len) {
                if (isPre) {
                    for (int i = 0; i < (len - len_1); i++) {
                        str = let + str;
                    }
                } else {
                    for (int i = 0; i < (len - len_1); i++) {
                        str = str + let;
                    }
                }
            }
            return str;
        }
    
        /**
         * @return the exceptionMessage
         */
        public String getExceptionMessage() {
            return exceptionMessage;
        }
    
    }

    4.Excel辅助工具类ExcelReaderUtil,我把这些代码做了一下处理,现在可以直接一次性读取3个sheet的内容,直接调用readExcel()方法即可

    public class ExcelReaderUtil {
    
        //excel2003扩展名
        public static final String EXCEL03_EXTENSION = ".xls";
        //excel2007扩展名
        public static final String EXCEL07_EXTENSION = ".xlsx";
    
    
    
        /**
         * @Author cjw
         * @Description 获取整个Excel的内容
         * @Date 10:18 2019/1/23
         * @Param [file]
         * @return 目前最多只读取三个sheet,可以自行扩展
         **/
        public static ImportExcelData readExcel(MultipartFile file) throws Exception {
            // 获取文件名
            if (file == null) {
                return null;
            }
            String fileName = file.getOriginalFilename();
            // 获取文件后缀
            String prefix = fileName.substring(fileName.lastIndexOf("."));
            if (!prefix.toLowerCase().contains("xls") && !prefix.toLowerCase().contains("xlsx")) {
                throw new Exception("文件格式错误,fileName的扩展名只能是xls或xlsx。");
            }
            // 防止生成的临时文件重复
            final File excelFile = File.createTempFile(System.currentTimeMillis() + "", prefix);
            file.transferTo(excelFile);
    
            Map<String, List<List<String>>> result = new HashMap<>();
            if (fileName.endsWith(EXCEL03_EXTENSION)) { //处理excel2003文件
                ExcelXlsReader excelXls = new ExcelXlsReader();
                result = excelXls.process(excelFile);
            } else if (fileName.endsWith(EXCEL07_EXTENSION)) {//处理excel2007文件
                ExcelXlsxReader excelXlsxReader = new ExcelXlsxReader();
                result = excelXlsxReader.process(excelFile);
            } else {
                throw new Exception("文件格式错误,fileName的扩展名只能是xls或xlsx。");
            }
            ImportExcelData data = new ImportExcelData();
            for (Map.Entry<String, List<List<String>>> entry : result.entrySet()) {
                if ("first".equals(entry.getKey())) {
                    data.setFirstSheetList(result.get(entry.getKey()));
                }
                if ("second".equals(entry.getKey())) {
                    data.setSecondSheetList(result.get(entry.getKey()));
                }
                if ("third".equals(entry.getKey())) {
                    data.setThirdSheetList(result.get(entry.getKey()));
                }
            }
            //删除临时转换的文件
            if (excelFile.exists()) {
                excelFile.delete();
            }
            return data;
        }
    
    
    }

    4.1sheet内容封装类

    @Data
    public class ImportExcelData {
    
        //第一个sheet
        private List<List<String>> firstSheetList;
    
        //第二个sheet
        private List<List<String>> secondSheetList;
    
        //第三个sheet
        private List<List<String>> thirdSheetList;
    }

    5.测试

    上传了一个200M左右的Excel,可以看到,整个解析时间大概是一分多钟

    展开全文
  • POI 读取Excel文件

    2010-12-09 22:22:53
    POI 读取Excel文件 POI 读取Excel文件
  • 主要介绍了java使用poi读取ppt文件poi读取excel、word示例,需要的朋友可以参考下
  • POI读取word文件

    2015-07-13 11:33:07
    POI读取word文件,存入数据库,代码很简单,主要用于读取word文件里面索要读取的内容,数据库那块一带而过!
  • POI读取word文件内容

    2014-09-19 17:06:51
    POI读取word文件内容 word格式包括doc,docx两种。
  • poi读取excel文件

    2018-09-27 15:11:16
    最新版poi 相关6个jar包 for java。Java读取Excel表格数据时(.xls、.xlsx 格式),需要引用的jar包 亲测as上可以读取到2010excel内容,内附读取源码
  • POI读取Excel文件

    2020-02-26 12:36:44
    poi读取Excel文件出现这样的错误 The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI ...

    poi读取Excel文件出现这样的错误

    The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)
    

    原来写的是

    InputStream in = new FileInputStream(file);
                //获取文件
                HSSFWorkbook workbook = new HSSFWorkbook(in);
                //得到第一张表
                HSSFSheet sheet = workbook.getSheetAt(0);
    

    HSSFWorkbook 是用于2003的.xls文件读取
    XSSFWorkbook是用于2007.xlsx文件读取
    在这里插入图片描述
    这两个是不一样的

    所以在读取文件时先判断一下文件名

    展开全文
  • poi读取excel文件异常:读取EXCEL文件出错 Caused by: java.io.IOException: While trying to invoke ‘createWorkbook’ on factory org.apache.poi.xssf.usermodel.XSSFWorkbookFactory and arguments [C:\Users\...

    poi读取excel文件异常:读取EXCEL文件出错

    Caused by: java.io.IOException: While trying to invoke ‘createWorkbook’ on factory org.apache.poi.xssf.usermodel.XSSFWorkbookFactory and arguments [C:\Users\xxx\Desktop\xxx.xlsx, false]

    Caused by: java.lang.ClassNotFoundException: org.apache.poi.xssf.usermodel.XSSFWorkbookFactory

    原因是引入的poi相关jar包版本不一致导致,pom.xml配置文件引入jar包版本。
    在这里插入图片描述

    展开全文
  • Java用poi读取excel文件

    2010-06-17 15:10:06
    Java用poi读取excel文件Java用poi读取excel文件Java用poi读取excel文件
  • 使用POI读取excel文件内容.pdf
  • 利用POI读取Excel文件

    2015-02-16 20:02:33
    前几天实现了利用POI创建Excel文件,今天分享一下如何利用POI读取Excel文件。 要读取的文件内容,以下截图已给出: 下面讲读取文件内容的方法。 先创建一个读取Excel的工具类。 /** * 操作Excel表格的功能...
  • java 利用POI读取Word文件中的内容

    热门讨论 2010-06-21 08:54:08
    java 利用POI读取Word文件中的内容 java 利用POI读取Word文件中的内容
  • 主要介绍了Java中使用Apache POI读取word文件简单示例,本文着重介绍了一些必要条件,然后给出一个简单读取示例,需要的朋友可以参考下
  • POI读取Excel大文件.rar

    2016-09-21 18:40:25
    POI处理Excel大文件的问题和解决方法 来自 http://itindex.net/detail/52291-poi-excel-%E6%96%87%E4%BB%B6
  • Java POI 读取word文件

    2016-09-30 14:33:44
    Java POI 读取word文件 Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序Microsoft Office格式档案读和写的功能。 1.读取word 2003及word 2007需要的jar包  读取 2003 版本(.doc)的...
  • 使用POI 读取Excel文件数据/*POI常用类说明 类名 说明 HSSFWorkbook Excel的文档对象 HSSFSheet Excel的表单 HSSFRow Excel的行 HSSFCell Excel的格子单元 HSSFFont
  • POI读取Word文件之后,文件一直被占用,无法删除 使用poi读取word文件之后,文件就无法删除,一直正在使用 在操作完word文件之后也关闭了流,并在操作完成之后删除源文件,代码看着好像是没有问题 ...
  • POI处理Excel大文件的问题和解决方法,测试excel文件大小4.5M,14万条数据,没有问题。 将excel文件的内容转换成cvs格式文件
  • 使用poi读取excel文件

    万次阅读 2019-05-22 14:45:29
    注:读取文件格式是xls,如果xlsx格式文件,可以自己通过excel文件右键→另存为,转换一下格式 导包 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId&...
  • POI读取Excel文件的带注释小例子.pdf
  • 将excel文件中的内容通过java文件读取出来,包括总行数,列数,单元格内容,合并单元格,行高,列宽,图片等信息。
  • 主要介绍了java使用POI读取properties文件并写到Excel的方法,涉及java操作properties文件及Excel文件的相关技巧,需要的朋友可以参考下
  • 使用POI对excel文件进行读取

    千次阅读 2018-01-31 11:09:32
    使用POI对excel文件进行读取 Excel转换为HTML表格(包括样式) Excel读取图片 Excel读取附件 使用POI对excel文件进行读取 excel转换HTML 代码块 ReadExcel2Html 类 ColorInfo 类 ColorUtil 类 OperaColor ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 37,888
精华内容 15,155
关键字:

poi读取大文件