package com.tebon.ams.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.util.SAXHelper;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: ${description}
 * @author: dfz
 * @create: 2018-12-14
 **/
@Slf4j
public class XLSX2CSV {
    /**
     * Uses the XSSF Event SAX helpers to do most of the work
     * of parsing the Sheet XML, and outputs the contents
     * as a (basic) CSV.
     */
    private List<String[]> rows = new ArrayList<String[]>();

private final OPCPackage xlsxPackage;

/**
     * Number of columns to read starting with leftmost
     */
    private int[] minColumns;

/**
     * Destination for data
     */
    private class SheetToCSV implements SheetContentsHandler {
        private String[] record;
        private int minColumns;
        private int thisColumn = 0;

public SheetToCSV(int minColumns) {
            super();
            this.minColumns = minColumns;
        }

@Override
        public void startRow(int rowNum) {
            record = new String[this.minColumns];
            // System.out.println("################################:"+rowNum);
        }

@Override
        public void endRow(int rowNum) {
            thisColumn = 0;
            if (!ObjectUtil.isEmpty(this.record) && !ObjectUtil.isEmpty(this.record[0])) {
                rows.add(this.record);
            }
            //一行结束要把此属性置""
            preXy = "";
            //System.out.println("**********************************");

}

//前一个单元格的xy
        private String preXy = "";
        //当前单元格的xy
        private String currXy = "";
        //前一个单元格的x
        private String preX = "";
        //当前单元格的x
        private String currX = "";
        //两个不为空的单元格之间隔了多少个空的单元格
        private int flag = 0;

@Override
        public void cell(String cellReference, String formattedValue, XSSFComment comment) {

//与判断空单元格有关
            if ("".equals(preXy)) {
                preXy = cellReference;
            }
            currXy = cellReference;
            preX = preXy.replaceAll("\\d", "").trim();
            currX = currXy.replaceAll("\\d", "").trim();
            int preAscii = 0;
            int curAscii = 0;
            preAscii = excelColStrToNum(preX, preX.length());
            curAscii = excelColStrToNum(currX, currX.length());
            flag = curAscii - preAscii;
            if (flag != 0 && flag != 1 && flag > 0) {
                //isSkipCeil = true;
                for (int i = 0; i < (flag - 1); i++) {
                    //appStr = appStr + ",";
                    record[thisColumn] = null;
                    thisColumn++;
                }
            }
            preXy = cellReference;
            if (thisColumn < this.minColumns)
                record[thisColumn] = formattedValue.trim();
            thisColumn++;

}

@Override
        public void headerFooter(String text, boolean isHeader, String tagName) {
            // Skip, no headers or footers in CSV
        }

}

/**
     * Creates a new XLSX -> CSV converter
     *
     * @param pkg        The XLSX package to process
     * @param minColumns The minimum number of columns to output, or -1 for no minimum
     */
    public XLSX2CSV(OPCPackage pkg, int... minColumns) {
        this.xlsxPackage = pkg;
        this.minColumns = minColumns;
    }

/**
     * Parses and shows the content of one sheet
     * using the specified styles and shared-strings tables.
     *
     * @param styles
     * @param strings
     * @param sheetInputStream
     */
    public void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, SheetContentsHandler sheetHandler, InputStream sheetInputStream)
            throws IOException, ParserConfigurationException, SAXException {
        DataFormatter formatter = new DataFormatter();
        InputSource sheetSource = new InputSource(sheetInputStream);
        try {
            XMLReader sheetParser = SAXHelper.newXMLReader();
            ContentHandler handler = new XSSFSheetXMLHandler(styles, null, strings, sheetHandler, formatter, false);
            sheetParser.setContentHandler(handler);
            sheetParser.parse(sheetSource);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
        }
    }

/**
     * Initiates the processing of the XLS workbook file to CSV.
     *
     * @throws IOException
     * @throws OpenXML4JException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    public Map<Integer, List<String[]>> process() throws IOException, OpenXML4JException, ParserConfigurationException, SAXException {
        Map<Integer, List<String[]>> map = new HashMap<>();
        ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(this.xlsxPackage);
        XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);
        StylesTable styles = xssfReader.getStylesTable();
        XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
        int index = 0;
        int length = 0;
        while (iter.hasNext()) {
            InputStream stream = iter.next();
            String sheetName = iter.getSheetName();
            //this.output.println();
            //this.output.println(sheetName + " [index=" + index + "]:");
            if (this.minColumns.length < index + 1) {
                log.info("请求参数不符合sheet页数...直接退出");
                return map;
            }
            processSheet(styles, strings, new SheetToCSV(this.minColumns[index]), stream);
            stream.close();
            //map.put(index, this.rows.subList(length, this.rows.size()));
            length = length + this.rows.size();
            map.put(index, this.rows);
            this.rows = new ArrayList<String[]>();
            ++index;
        }
        return map;
    }

/**
     * 得到excel的记录
     *
     * @param excelPath
     * @param minColumns 输出多少列
     * @return
     * @throws Exception
     */
    public static Map<Integer, List<String[]>> getRecords(String excelPath, int... minColumns) throws Exception {
        File xlsxFile = new File(excelPath);
        if (!xlsxFile.exists()) {
            System.err.println("Not found or not a file: " + xlsxFile.getPath());
            return null;
        }
        // The package open is instantaneous, as it should be.
        OPCPackage p = OPCPackage.open(xlsxFile.getPath(), PackageAccess.READ);
        XLSX2CSV xlsx2csv = new XLSX2CSV(p, minColumns);
        Map<Integer, List<String[]>> map = xlsx2csv.process();
        p.close();
        return map;
    }

/**
     * 得到excel的记录
     *
     * @param minColumns 输出多少列
     * @return
     * @throws Exception
     */
    public static Map<Integer, List<String[]>> getRecords(File file, int... minColumns) throws Exception {
        OPCPackage p = OPCPackage.open(file);
        XLSX2CSV xlsx2csv = new XLSX2CSV(p, minColumns);
        Map<Integer, List<String[]>> map = xlsx2csv.process();
        p.close();
        return map;
    }

/**
     * Excel列号数字与字母互换
     * Excel column index begin 1
     *
     * @param colStr
     * @param length
     * @return
     */
    public static int excelColStrToNum(String colStr, int length) {
        int num = 0;
        int result = 0;
        for (int i = 0; i < length; i++) {
            char ch = colStr.charAt(length - i - 1);
            num = (int) (ch - 'A' + 1);
            num *= Math.pow(26, i);
            result += num;
        }
        return result;
    }

public static void main(String[] args) throws Exception {

Map<Integer, List<String[]>> map = getRecords("C:\\Users\\lenovo\\Desktop\\333.xlsx", 63, 4, 4);
        int preAscii = excelColStrToNum("AC", 2);
        int curAscii = excelColStrToNum("Z", 1);
        System.out.println(preAscii);
        System.out.println(curAscii);
    }

}

参考文档:https://blog.csdn.net/daiyutage/article/details/53023020

Excel大批量数据导出的更多相关文章

  1. 大批量数据导出到Excel的实现

    在平时的项目中,将数据导出到Excel的需求是很常见的,在此对一些常见的方法做以总结,并提供一种大数据量导出的实现. OLEDB   使用OLEDB可以很方便导出Excel,思路很简单,处理时将Exc ...

  2. 大批量数据导出excel

    有次面试时,老板问我大批量数据一次性导出会有什么问题 感谢度娘提供,感谢原博主提供 https://www.cnblogs.com/zou90512/p/3989450.html

  3. Java:导出Excel大批量数据的优化过程

    背景 团队目前在做一个用户数据看板(下面简称看板),基本覆盖用户的所有行为数据,并生成分析报表,用户行为由多个数据来源组成(餐饮.生活日用.充值消费.交通出行.通讯物流.交通出行.医疗保健.住房物业. ...

  4. jxl写入excel实现数据导出功能

    @RequestMapping(params = "method=export", method = RequestMethod.GET) public void exportCo ...

  5. Java 导出大批量数据excel(百万级)(转载)

    参考资料:http://bbs.51cto.com/thread-1074293-1-1.html                 http://bbs.51cto.com/viewthread.ph ...

  6. Java实现大批量数据导入导出(100W以上) -(三)超过25列Excel导出

    前面一篇文章介绍大数据量导出实现: Java实现大批量数据导入导出(100W以上) -(二)导出 这篇文章在Excel列较少时,按以上实际验证能很快实现生成.但如果列较多时用StringTemplat ...

  7. Java 使用stringTemplate导出大批量数据excel(百万级)

    目前java框架中能够生成excel文件的的确不少,但是,能够生成大数据量的excel框架,我倒是没发现,一般数据量大了都会出现内存溢出,所以,生成大数据量的excel文件要返璞归真,用java的基础 ...

  8. Java实现大批量数据导入导出(100W以上) -(二)导出

    使用POI或JXLS导出大数据量(百万级)Excel报表常常面临两个问题: 1. 服务器内存溢出: 2. 一次从数据库查询出这么大数据,查询缓慢. 当然也可以分页查询出数据,分别生成多个Excel打包 ...

  9. [django]数据导出excel升级强化版(很强大!)

    不多说了,原理采用xlwt导出excel文件,所谓的强化版指的是实现在网页上选择一定条件导出对应的数据 之前我的博文出过这类文章,但只是实现导出数据,这次左思右想,再加上网上的搜索,终于找出方法实现条 ...

随机推荐

  1. 【codechef】FN/Fibonacci Number

    题意 给出 c 和 P ,求最小的非负整数 n 使得 \(Fib(n)=c(mod~ P)\) 其中 P 是质数且 模 10 等于一个完全平方数(也就是说 P 的末位是个完全平方数,那么只能是 1 或 ...

  2. OAuth 2.0详解

    OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版. 本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为R ...

  3. 写一个python 爬虫爬取百度电影并存入mysql中

    目标是利用python爬取百度搜索的电影 在类型 地区 年代各个标签下 电影的名字 评分 和图片连接 以及 电影连接 首先我们先在mysql中建表 create table liubo4( id in ...

  4. 微信小程序rich-text 文本首行缩进和图片居中

    微信小程序开发使用rich-text组件渲染html格式的代码,常常因为不能自定义css导致文本不能缩进,以及图片不能居中等问题,这里可以考虑使用js的replace方法,替换字符串,然后在渲染的同时 ...

  5. java 常用工具类

    1. org.apache.commons.collections4包提供CollectionUtils.MapUtils.ListUtils.SetUtils等工具类: 2. org.apache. ...

  6. 激活windows专业版(激活windows10专业版,解决“我们无法在此设备上激活windows因为无法连接到你的组织的激活服务器 ”)

    本来系统用的好好的,但是前几天系统突然提示我要去取设置里面激活windows,我就想:我的系统好像是原厂正版的吧,怎么就过期了呢?没办法只能搜索下怎么激活,去系统城,各大网站什么的试了好多密钥全部不行 ...

  7. RabbitMQ一个简单可靠的方案(.Net Core实现)

    前言 最近需要使用到消息队列相关技术,于是重新接触RabbitMQ.其中遇到了不少可靠性方面的问题,归纳了一下,大概有以下几种: 1. 临时异常,如数据库网络闪断.http请求临时失效等: 2. 时序 ...

  8. .NET英文技术文章导读(2017-03-23)

    关键字:VS2017.扩展.Service Fabric.Unit Test.ELMAH Web开发人员必装的5个VS2017扩展 作者:Jeffrey T. Fritz 链接:https://blo ...

  9. 二.Nginx反向代理和静态资源服务配置

    2018年03月31日 10:30:12 麦洛_ 阅读数:1362更多 所属专栏: nginx   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/M ...

  10. 阿里云+WordPress搭建个人博客

    搭建过程: 第一步:首先你需要一台阿里云服务器ECS,如果你是学生,可以享受学生价9.5元/月 (阿里云翼计划:https://promotion.aliyun.com/ntms/act/campus ...