记一次java使用POI读取Excel-xlsx

本文记录了一次使用Java的POI库处理xlsx格式(包括Strict xlsx)Excel文件的经历。在尝试读取大量数据时,面临了内存泄露问题,选择流式读取并转换为XML进行解析。同时,文章提到了时间戳转换、处理Excel数据类型以及解决依赖包冲突的方法,展现了POI库在处理Excel文件时的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Excel分类:xls格式,xlsx格式,(Strict xlsx格式这次也接触到了)

2、两种类型的文件有两种不同的方式去读,另外也要注意文件创建的Excel版本

xls:HSSFReader

xlsx:XSSFReader

3、需求:将定量数据导入到mysql中

要求:使用poi去读取strict Excel格式的文件(xlsx),为了安全起见,觉得有种可行性,所以采取这种方式

尝试过后,一是不知道数据类型难以处理,二是网上很少有资料可供查询,最后实在读取不了,改为了读普通的xlsx

4、读取还是有两种方式可以采取

(1)数据量很小时,直接读就行了。

https://www.cnblogs.com/muliu/p/6812347.html

(2)数据量很大时,超过65535(16位)时,会造成内存泄露。

          采用流式读取,其实Excel2007版的xlsx底层采用的是xml,故将xlsx转为xml,读取xml,通过自定义解析器去读取。

读取后注意类型的转换

public class ExampleEventUserModel{
    public void processOneSheet(String filename) throws Exception {
        OPCPackage pkg = OPCPackage.open(filename);
        XSSFReader r = new XSSFReader( pkg );
        SharedStringsTable sst = r.getSharedStringsTable();
 
        XMLReader parser = fetchSheetParser(sst);
 
        // 获得第一个sheet
        InputStream sheet2 = r.getSheet("rId1");
        InputSource sheetSource = new InputSource(sheet2);
        parser.parse(sheetSource);
        sheet2.close();
    }
 
    public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException {
        XMLReader parser =
                XMLReaderFactory.createXMLReader(
                        "org.apache.xerces.parsers.SAXParser"
                );
        ContentHandler handler = new SheetHandler(sst);
        parser.setContentHandler(handler);
        return parser;
    }
 
    /**
     * 处理sax的handler
     */
    private static class SheetHandler extends DefaultHandler {
        private SharedStringsTable sst;
        private String lastContents;
        private boolean nextIsString;
 
        private SheetHandler(SharedStringsTable sst) {
            this.sst = sst;
        }
 
        //元素开始时的handler
        public void startElement(String uri, String localName, String name,
                                 Attributes attributes) throws SAXException {
            // c => 单元格
            if(name.equals("c")) {
                System.out.print(attributes.getValue("r") + " - ");
                // 获取单元格类型
                String cellType = attributes.getValue("t");
                if(cellType != null && cellType.equals("s")) {
                    nextIsString = true;
                } else {
                    nextIsString = false;
                }
            }
            lastContents = "";
        }
 
        //元素结束时的handler
        public void endElement(String uri, String localName, String name)
                throws SAXException {
            if(nextIsString) {
                int idx = Integer.parseInt(lastContents);
                lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
                nextIsString = false;
            }
 
            // v => 单元格内容
            if(name.equals("v")) {
                System.out.println(lastContents);
            }
        }
 
        //读取元素间内容时的handler
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            lastContents += new String(ch, start, length);
        }
    }
 
    public static void main(String[] args) throws Exception {
        ExampleEventUserModel example = new ExampleEventUserModel();
        example.processOneSheet("d://large.xlsx");
    }
 
}

5、其他问题

(1)时间戳类型的转换,excel中存的是long串

         解决方案:java类Timestamp 转换之后可以直接存到数据库里,对应datetime类型。

Long createTime = Long.valueOf(rowlist.get(i));
Timestamp timestamp = new Timestamp(createTime);

时间戳类型大小比较

timestamp.before(timestamp2)

timestamp.after(timestamp2)

 

(2)存到数据库遇到障碍:在静态类中无法调用dao层数据库语句

解决:将读到的数据,存到Entity中,然后存到List链中,然后返回出去,第一次体会到List的强大,40万条大概占用内存400M

粗暴了一点,哈哈哈哈

(3)依赖包问题:有些依赖包不支持XSSF方式读取文件

最后用的3.15-beta2....引入这一个依赖就ok,就包含了poi,poi-ooxml-schemas

开始都引入了,反而报缺少schemas的错误了。删去就行了。

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.15-beta2</version>
</dependency>

6、碰完错才发现poi还是蛮强大的,会用了就好了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值