『Java』Zip中Excel文件的解析


前言

永远相信美好的事情即将发生


背景

自从上一次尝试使用 EasyExcel 对文件下载接口进行解析从而完成数据的爬取之后,我便放弃了最开始使用的数据接口解析爬取,转而投入到了 Excel 的怀抱(前提是页面要有下载文件的入口)。

然而在后续中的爬取中又出现了新的问题,那就是有些下载源因为数据量过大或其他原因,提供的是 ZIP 的下载,Excel 文件包含在了 ZIP 中,那么我们就不能在使用 EasyExcel 直接去解析,而是要采取新的方法。



思路

关于 ZIP 文件中 Excel 的解析,在我的一番深思熟虑后想到了两种方案

  • 下载 ZIP 到某个位置,解压出 Excel 后读取
  • 对下载 ZIP 的流进行处理,获取到其中的 Excel 流文件,使用 EasyExcel 进行读取

这两种方法各有各的优劣,前者相对来说实现难度较低(虽然我也不会),但是会占用额外的空间进行存储,就算进行删除操作也是会存在一定的风险;而后者则较为方便,无需下载,但是会比前者的难度稍微高点。这里我们采取的是第二种方式,直接解析ZIP中的流。

历程

Excel及ZIP的创建

对同一个文件来说,从接口获取到的流和从本地读取到的流基本一致,因此为了更直观的看到效果,我们采用了本地创建 ZIP 的方式,后期使用的时候可以更改为直接从接口获取流。
首先我们创建一个 Excel 文件,并将其压缩为 ZIPExcel 数据如下

在这里插入图片描述

EasyExcel的配置

这里大家可以参照我以前的一篇博客 『Java』EasyExcel基础——读 ,只要大的版本号保持一致应该就没什么问题。


在这里插入图片描述

实体类及解析器的创建

首先我们需要根据 Excel 的表头创建实体类,这里使用的是 lombok,没有导入的可以先在 idea 中导入一下

/**
 * @Description: 测试实体类
 * @Author: Am0xil
 * @Date: 2020/9/8
 **/
@Data
public class TestEntity {

    @ExcelProperty(value = "姓名")
    private String userName;
    @ExcelProperty(value = "性别")
    private String gender;
    @ExcelProperty(value = "年龄")
    private String age;
    @ExcelProperty(value = "籍贯")
    private String address;
    
}

然后我们需要创建 **EasyExcel** 的解析器,因为这次只是演示,因此就不在 **Dao** 层添加数据写入的方法,需要的可以手搓一个,也可以参考以前的那篇博客
/**
 * @Description: Excel解析器
 * @Author: Am0xil
 * @Date: 2020/9/9
 **/
@Slf4j
public class TestExcelListner extends AnalysisEventListener {

    @Override
    public void invoke(Object o, AnalysisContext analysisContext) {
        log.info(((TestEntity)o).toString());
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
		log.info("解析完成");
    }

Service层实现

重点就在于实现层,具体的实现方法和之前直接解析 Excel 的过程差不多,只不过多了一步对 ZIP 的解析,首先会将文件转化为 ZipInputStream ,这是一种专门用于读取压缩文件的流,然后会在这个 ZipInputStream 中找到存储我们目标 Excel 的流文件进行解析,从而获取数据,具体代码如下

/**
 * @Description: 解析 ZIP 中的 Excel 文件
 * @Author: Am0xil
 * @Date: 2020/9/8
 **/
@Service
public class TestServiceImpl implements TestService {
    @Override
    public void zipExcelTest() throws Exception {
        // 使用 File 进行本地 ZIP 文件的读取
        String fileName = "C:\\Users\\King\\Desktop\\测试.zip";
        File file = new File(fileName);
        // 将 file 文件转换为 ZipInputStream 流,ZipInputStream 为压缩文件输入流,专门用于读取压缩文件
        // 如果 Excel 中包含特殊字符,需要手动去调整编码格式,这里我们暂且使用默认的 utf-8
        ZipInputStream zipStream = new ZipInputStream(new FileInputStream(file));
        // 因为流只可被读取一次的特性,因此我们需要创建一个 ZipEntry 去接收
        ZipEntry zipEntry;
        // 循环读取 ZIP 文件中的每一个子文件,若文件不为空且文件名为我们需要的那个("测试.xlsx"),则开始解析
        while ((zipEntry = zipStream.getNextEntry()) != null){
            if (Objects.equals(zipEntry.getName(),"测试.xlsx")){
                // 逐字节读取 ZipInputStream 文件,并将结果存储至一个字节数组缓冲区(ByteArrayOutputStream)中
                byte[] buffer = new byte[1024];
                int len;
                ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
                while ((len = zipStream.read(buffer)) != -1){
                    byteStream.write(buffer,0,len);
                }
                // 关闭流
                byteStream.close();
                // 创建 Excel 解析器对象
                TestExcelListner testExcelListner = new TestExcelListner();
                ExcelReader excelReader;
                // 将之前的 ByteArrayOutputStream 对象转化为 byte数组,然后使用 EasyExcel 进行解析
                excelReader = EasyExcel.read(new ByteArrayInputStream(byteStream.toByteArray()), TestEntity.class,testExcelListner).build();
                ReadSheet readSheet = EasyExcel.readSheet().build();
                excelReader.read(readSheet);
            }
        }
    }
}

执行结果

执行结果如图所示
在这里插入图片描述
从图中我们可以看到,这样我们就获取到了 ZIPExcel 的数据


总结

  • 在解析过程中一定要对流有着很清晰的认知,在下就是因为对 IO 掌握的不是很熟,导致走了很多弯路
  • EasyExcel 的报错不是很直观,一般都会报 “无法获取当前Excel的类型” 这个错误,使用的时候一定多加小心,报错了基本上都是流转换的时候所引发的
  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

3价Fe离子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值