最近记录了一些java中常踩的坑、设计思路和小知识点,大家可以看看
详细记录一次接入xxl-job的踩坑路径
30s快速解决循环依赖
idea中一个小小的操作竟能解决如此多的问题
docker中的服务接入xxljob需要注意的一点
关于一次fullgc的告警分析
mysql中的int类型竟变成了它?
jpa中的字段总是自己莫名更新?
获取不到类上的注解?空指针?
学会这招,再也不怕依赖冲突!
redis的热点key还能这么处理?
领导让我设计一个任务系统
当服务重启时,大部分人没考虑这点
参数还能这么优雅校验?
文件上传报错,全局异常处理!
常见的点赞功能如何实现,如何防止刷赞
需求背景
在涉及到多文件上传时,为了效率,往往会打成压缩包上传,而有些场景需要将压缩包中文件的层级结构保留并做以展示,以供用户下载前预览。
若按照正常流程,需要业务线服务端将压缩包下载并解压,然后得到文件大小、类型、相对路径等信息后做层级封装,返回给前端展示。
但是此场景下的压缩包,往往文件数量和体积都不会小,所以服务端去一一下载并解压就会很耗费资源。
于是此方案目的就是通过不完全下载压缩包来获取压缩包内文件结构。其原理是zip文件的尾部字节里包含了整个文件夹结构信息的结构体,所以服务端只需要从存储下载压缩包尾部的一部分字节流,分片下载,并按照zip结构体的定义解析出来,即可得到展示文件目录所需要的信息,无需下载整个压缩包并解压。
这种方式省时省流,服务端只需要耗费极少的资源,在压缩包第一次上传的时候解析存储一次即可。
实现
package com.iqiyi.digitalassets.utils.util;
import com.alibaba.fastjson.JSON;
import com.iqiyi.digitalassets.utils.constants.Constants;
import com.iqiyi.digitalassets.utils.util.BitConverter;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* @Classname ZipFileStructureUtils
* @Description 实现通过不完全下载压缩文件,获取压缩文件内文件结构,适配ZIP、ZIP64
* 1、zip文件在整个文件的尾部字节里包含了整个文件夹结构信息的结构体 central directory
* 2、从远程文件尾部读取部分字节找到end of central directory(EOCD), ZIP为0x06054b50,ZIP64为0x06064b50
* 3、ZIP、ZIP64都会包含signature 0x06054b50,但是ZIP64在signature offset + 16 处开始的4字节表示central directory开始相对与整个文件的偏移量的值会是0xffffffff
* 4、根据EOCD signature的位置,获取整个CD的开始位置和大小,计算出下一次需要从网络中读取的字节范围
* 5、从读取出来的CD字节数据组中,根据结构体定义,提取出来zip文件内文件夹结构信息
* @Link 维基百科zip结构定义 https://en.wikipedia.org/wiki/ZIP_(file_format)
*
* End of central directory record (EOCD)
* Offset Bytes Description[31]
* 0 4 End of central directory signature = 0x06054b50
* 4 2 Number of this disk (or 0xffff for ZIP64)
* 6 2 Disk where central directory starts (or 0xffff for ZIP64)
* 8 2 Number of central directory records on this disk (or 0xffff for ZIP64)
* 10 2 Total number of central directory records (or 0xffff for ZIP64)
* 12 4 Size of central directory (bytes) (or 0xffffffff for ZIP64)
* 16 4 Offset of start of central directory, relative to start of archive (or 0xffffffff for ZIP64)
* 20 2 Comment length (n)
* 22 n Comment
*
* Zip64 End of central directory record (EOCD64)
* Offset Bytes Description
* 0 4 End of central directory signature = 0x06064b50
* 4 8 Size of the EOCD64 - 12
* 12 2 Version made by
* 14 2 Version needed to extract (minimum)
* 16 4 Number of this disk
* 20 4 Disk where central directory starts
* 24 8 Number of central directory records on this disk
* 32 8 Total number of central directory records
* 40 8 Size of central directory (bytes)
* 48 8 Offset of start of central directory, relative to start of archive
* 56 n Comment (up to the size of EOCD64)
*
* Central directory file header
* Offset Bytes Description[31]
* 0 4 Central directory file header signature = 0x02014b50
* 4 2 Version made by
* 6 2 Version needed to extract (minimum)
* 8 2 General purpose bit flag
* 10 2 Compression method
* 12 2 File last modification time
* 14 2 File last modification date
* 16 4 CRC-32 of uncompressed data
* 20 4 Compressed size (or 0xffffffff for ZIP64)
* 24 4 Uncompressed size (or 0xffffffff for ZIP64)
* 28 2 File name length (n)
* 30 2 Extra field length (m)
* 32 2 File comment leng