Zip格式结构图总览 Zip文件结构详解
【前言】
一、Zip格式结构图总览
二、Zip文件结构详解
(相关资料图)
zip格式压缩包主要由三大部分组成:数据区、中央目录记录区(也有叫核心目录记录)、中央目录记录尾部区
1、数据区
数据区是由一系列本地文件记录组成,本地文件记录主要是记录了压缩前后文件的元数据以及存放压缩后的文件,组成部分也分为三大部分:本地文件头、文件数据、文件描述1.1、本地文件头本地文件头主要是记录了压缩文件的元数据: 1)0~3:4个字节,用来存放本地文件头标识:0x04034b50,用于解压时候,读取判断文件头的开始 2)4~5:2个字节,记录解压缩文件所需的最低支持的ZIP规范版本,apk压缩版本默认是20, 即Deflate压缩方式
3)6~7:2个字节,记录通用标志位,第0位为1时(即二进制:00000000 00000001),表示文件被加密,解压时候需要解密;第3位为1时候(即二进制:00000000 00000100),表示有数据描述部分,那么本地文件头中的 CRC-32、压缩大小和未压缩大小字段都被设置为0(虽然zip规范是这么定义,但是发现有些压缩包即使声明有数据描述部分,但是本地文件头的CRC-32、压缩大小和未压缩大小依然还是设置为真实值) , 正确的值被放在紧跟在压缩数据之后的数据描述部分,apk的通用标志位默认传0即可,也有传2048、2056,目前第15位是PKWARE保留位,没啥意义,更多通用标志位含义可见这里 4)8~9:2个字节,记录压缩包所用到的压缩方式,apk默认Deflate压缩,传8即可, 要是传0,则是不压缩,各种压缩方式对应数值如下:
5)10~11:2个字节,记录文件最后修改时间,是MS-DOS格式编码的时间 6)12~13:2个字节,记录文件最后修改日期,是MS-DOS格式编码的日期 7)14~17:4个字节,记录文件未压缩时的CRC-32校验码8)18~21:4个字节,记录文件压缩后的大小9)22~25:4个字节,记录文件未压缩的大小10)26~27:2个字节,记录文件名的长度(假设文件名长度为n) 11)28~29:2个字节,记录扩展区的长度(假设扩展区长度为m) 12)30~30+n: n个字节,记录文件名13)30+n~30+n+m: m个字节,记录扩展数据1.2、文件数据文件数据紧跟在本地文件头之后,一般是压缩后的文件数据或压缩方式选择不压缩时候,用来存储未压缩文件数据。 1.3、文件描述文件描述符仅在通用位标志的第 3 位被设置为1时才存在。 它是字节对齐的,紧跟在文件数据的最后一个字节之后。当且仅当无法在 .ZIP 文件中查找时才使用此描述符,例如:当输出 的.ZIP 文件是标准输出或不可查找设备时使用文件描述,换句话说,正常情况下都不需要使用 数据描述符标识不一定有,因为一开始规范是没有的,后面才加上去的
2、中央目录记录区(也称核心目录记录区 )
中央目录记录区是有一系列中央目录记录所组成,一条中央目录记录对应数据区中的一个压缩文件记录,中央目录记录由以下部分构成: 1)0~3:4个字节,记录核心目录文件头标识:0x02014b50,用于解压时候,查找判断是否是中央目录的开始位置 2)4~5:2个字节,记录压缩所用的版本,同数据区本地文件头的解压所需版本,apk设置203)6~7:2个字节,记录解压所需的最小版本,同数据区本地文件头的解压所需版本,apk设置204) 8~9:2个字节,通用位标记,同数据区本地文件头的通用位标记 5)压缩方法、文件最后修改时间、文件最后修改日期、CRC-32校验码、压缩后大小、未压缩大小、文件名长度、扩展区长度,这几个字段的含义都等同于数据区本地文件头对应字段的含义 6)32~33:2个字节,记录文件注释的长度7)34~35:2个字节,记录文件开始位置的磁盘编号,一般传0即可 8)内部文件属性、外部文件属性,一般也是传0即可 9)42~45:4个字节,记录数据区本地文件头相对于压缩包开始位置的偏移量
3、中央目录记录尾部区
中央目录记录尾部主要作用是用来定位中央目录记录区的开始位置,同时记录压缩包的注释内容
1)0~3:4个字节,中央目录记录尾部开头标记:0x06054b50,用于解压时,查找判断中央目录尾部的起始位置 2)4~5:2个字节,记录中央目录记录尾部区所在磁盘编号3)6~7:2个字节,记录中央目录开始位置所在的磁盘编号4)8~9:2个字节,该磁盘上所记录的核心目录数量5)10~11:2个字节,zip压缩包中的文件总数6)12~15:4个字节,整个中央目录的大小(以字节为单位)7)16~19:4个字节,中央目录开始位置相对位移8)20~21:2个字节,注释内容的长度(假设长度为n) 9)22~22+n:n个字节,注释内容
三、压缩包解压过程
1、先从中央目录尾部区着手,目标是找到中央目录尾部开头标记:0x06054b50,从上述对zip压缩包结构分析可知,中央目录尾部区除了注释内容之外,固定大小占22个字节,那么假如注释内容为空的时候,将指针从文件尾部往前移动22个字节,然后读取4个字节的数据,就正好是中央目录尾部开头标记:0x06054b50,但是注释内容是否为空在实际操作中是不可得知的,所以只能设置一个循环,每次递增一个字节,不断推测注释内容的长度,又因为注释长度用2个字节表示,那么注释长度最大只能是65535个字节,所以可以在0~65535这个范围内不断推测注释内容的长度. 下面是java代码实现的查找中央目录尾部开始位置的案例:
/** * 查找中央目录结尾的开始位置 * @param zipContents * @return */ private static int findZipEndOfCentralDirectoryRecord(ByteBuffer zipContents) {//判断是否小端模式排列 assertByteOrderLittleEndian(zipContents); int archiveSize = zipContents.capacity(); //由于核心目录尾部大小至少是22个字节,小于22就是没意义的 if (archiveSize < 22) {return -1; } //注释内容长度只可能是: 【压缩包大小 - 核心目录尾部固定大小(22字节)】与 【注释内容最大长度】中的最小值 int maxCommentLength = Math.min(archiveSize - 22, 65535); //假如没有注释内容,那么核心目录尾部开始位置是:压缩包大小 -22 int eocdWithEmptyCommentStartPosition = archiveSize - 22; // 循环查找,假设没有注释内容到每次递增一个字节的注释内容,查找出:核心目录结尾标识0x06054b50 for (int expectedCommentLength = 0; expectedCommentLength < maxCommentLength; expectedCommentLength++) {int eocdStartPos = eocdWithEmptyCommentStartPosition - expectedCommentLength; // 核心目录结尾标志:0x06054b50(十进制为:101010256), 标志位长度为4个字节,int类型刚好4字节 // zipContents.getInt(eocdStartPos),即从eocdStartPos位置开始读取4个字节的内容 if (zipContents.getInt(eocdStartPos) == 101010256) {//核心目录结尾标志的开始位置偏移20个字节就是注释内容长度,因为注释内容长度是2个字节,对应就是short类型的大小 int actualCommentLength = getUnsignedInt16(zipContents, eocdStartPos + 20); // 要是从压缩包中读取到的注释长度跟循环查找计算出的注释长度一致,那么就是找到了确切的核心目录结尾标记的开始位置了 if (actualCommentLength == expectedCommentLength) {return eocdStartPos; } } } return -1; }static void assertByteOrderLittleEndian(ByteBuffer buffer) {if (buffer.order() != ByteOrder.LITTLE_ENDIAN) {throw new IllegalArgumentException("ByteBuffer byte order must be little endian"); } }
2、中央目录尾部开始位置找到之后,那么可以从中获取到中央目录的开始位置,中央目录的大小,以及中央目录记录条目总数3、接着,又可以从中央目录中读取到本地文件头相对压缩包开始位置的偏移量,那么就能读到本地文件记录,并从中解压出文件数据,大概的解压流程就到此结束啦
【扩展知识】
刚才在java举例中有涉及到一个小端排序问题,因为在Jvm中默认都是按大端模式储存, 而 .ZIP格式的数据是按小端模式编排的,所以需要手动对ByteBuffer中的数据进行小端排序,那么,什么是小端模式,什么是大端模式呢?
1、大端模式:Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端,大端模式是跟人读写习惯是一致的,比如:数字0x12345678 与 0x11223344,大端模式表示如下:
低地址 ----------------------------------------------------> 高地址0x12 | 0x34 | 0x56 | 0x78 | 0x11 | 0x22 | 0x33 | 0x44
2、小端模式:Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端,比如:数字0x12345678 与 0x11223344,小端模式表示如下:
低地址 ----------------------------------------------------> 高地址0x78 | 0x56 | 0x34 | 0x12 | 0x44 | 0x33 | 0x22 | 0x11
那么,为啥会存在大小端不统一的问题呢?
既然大小端都有存在的必要性,那大小端模式各有啥优势呢?
【注意】字符是只有1个字节,故对于字符不存在大小端模式之分,只有大于1个字节的才分大小端模式
【实践案例】
理论说了一大篇幅,想必各位看官已是头昏脑涨,咱们来动手分析一个压缩包看看,是否如咱们理论所言那般,下面是一个安卓安装包(.apk)的案例: 1、首先,先找到中央目录结尾标志:0x06054b50,因为zip格式是小端模式,那么,咱们看到的应该是:50 4B 05 06, 用010 Editor打开apk,成功查找到中央目录结尾标志从截图可以看到: 1)当前磁盘编号为:0x0000(即十进制:0) 2)中央目录开始位置的磁盘编号也是:0x0000(即十进制:0), 3)该磁盘上所记录的中央目录数量:0xD236(转为大端模式就是0x36D2,十进制:14034) 4)zip压缩包中的文件总数:0xD236(转为大端模式就是0x36D2,十进制:14034) 5)中央目录大小:0x7A1E1600(转为大端模式就是0x00161E7A,十进制:1449594), 6)中央目录开始位置的相对位移:0x2A03480C(转为大端模式就是0x0C48032A,十进制:206045994) 7)注释长度:0x0000(即长度为0) 2、从第一步中,咱们可以知道中央目录开始位置是在地址206045994,那么查一下这个地址: 从截图可以看到 ① 从地址206045994开始读取4个字节,得到0x504B0102, 按大端模式排序为:0x02014b50, 刚好就是前面提到的中央目录文件头标识② 压缩所用版本:0x1400(转为大端模式就是0x0014,十进制:20) ③ 解压所需版本:0x1400(转为大端模式就是0x0014,十进制:20) ④ 通用位标记:0x0808(十进制:2056, 那么就是第3位设置为1,说明数据区有文件描述符) ⑤ 压缩方法:0x0800(转为大端模式就是0x0008,十进制:8) ⑥ 文件最后修改时间:0x4B79(转为大端模式就是0x794B,二进制:0111100101001011)
按照上面的MS-DOS时间编码规则,对二进制01111 001010 01011进行 拆分计算,时:01111(十进制:15),分:001010(十进制:10),秒:01011(十进制:11,这是秒除以2的值,故实际秒为11 * 2 = 22),那么,文件的最后修改时间为:15:10:22⑦ 文件最后修改日期:0xE552(转为大端模式就是0x52E5,二进制:0101001 0111 00101),年:0101001(十进制:41,1980 + 41 = 2021),月: 0111(十进制:7),日:00101(十进制:5),那么文件的最后修改日期为:2021-7-5,比对一下跟压缩软件的结果是一致的 ⑧ CRC-32校验码:0x04D127C5(转为大端模式就是0xC527D104),跟上述压缩软件结果也是一致的 ⑨ 压缩后的大小:0x20E80900(转为大端模式就是0x0009E820, 十进制:649248,约为634.03KB) ⑩ 未压缩的大小:0xA0D91B00(转为大端模式就是0x001BD9A0, 十进制:1825184,约为1.74MB),跟上述压缩软件结果也是一致的 ⑪ 文件名长度:0x1400(转为大端模式就是0x0014,十进制:20) ⑫ 扩展区长度、文件注释长度、文件开始位置的磁盘编号、内部文件属性都是:0x0000 ⑬ 外部文件属性、本地文件头的相对位移都是:0x00000000 ⑭ 文件名:0x4D 45 54 41 2D 49 4E 46 2F 4D 41 4E 49 46 45 53 54 2E 4D 46, 这些是字符ASCII码,转为字符是:META-INF/MANIFEST.MF
【注意】假如文件名有中文的话,那这里存放UTF-8编码数据,中文一般先转换为Unicode编码字符,然后用UTF-8编码方式存储(Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储, UTF-8是unicode的一种实现方式,unicode实现方式还有UTF-16和UTF-32)
【UTF-8小知识】UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。 UTF-8的编码规则很简单,只有2条:
1️⃣对于单字节的符号,字节的第1位(字节的最高位)设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。 2️⃣对于n字节的符号(n>1),第1个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码 比如:已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第3行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要3个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后1个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5
⑮ 因为扩展区长度为0,所以文件名后面紧跟压缩之后的文件数据,由上面分析的压缩长度为649248,所以后面649248个字节的数据都是文件数据
⑯ 因为是本地文件头的通用标志位第3位设置为1,所以存在数据描述区,数据描述区标识:0x504B0708(转换为大端模式:0x08074b50)
⑰ 数据描述符中的CRC-32校验码、压缩大小、未压缩大小跟本地文件头的值一致
标签:
相关推荐:
最新新闻:
- 4k分辨率是多少?真4k与假4k区别介绍_天天讯息
- 世界即时看!Maven默认的仓库位置在哪里?Maven默认仓库改成自己的仓库步鄹的方法
- Zip格式结构图总览 Zip文件结构详解
- 热门看点:商标注册查询入口官网在哪里?商标注册查询入口官网地址及查询方法
- 每日消息!nix系统上加载/管理模块的命令 linux常用命令之module
- mysql-uroot-p命令怎么下载?MySQL数据库安装教程_世界即时看
- 行式数据库系统中的列式存储——Clickhouse-世界热讯
- 《碟中谍7:致命清算》海报曝光 阿汤哥再次挑战极限_世界快看
- 天天最新:《街头霸王6》开发者实机演示 “桑吉尔夫 Vs 玛丽莎”
- 什么是BT?BT、FTP、PUB的下载方式有哪些?
- 天天观点:java中BigDecimal的4个造方法 你知道吗?
- 环球微速讯:在阿里巴巴图标库创建自己的工程 并导入第三方图标
- 今日快看!CST怎么用?CST使用心得及使用方法
- word文档中的大括号怎么打?六角括号怎么用键盘打?
- 全球快看:《速度与激情10》新海报发布 终途启程家人一直在身边
- 昆汀准备拍他“最后一部”电影了!今秋开机
- 鱼骨图绘制有什么技巧?3种类型的鱼骨图制作思维导图示例
- 《极乐迪斯科》开发商法律纠纷结束:主创还清欠款-环球新消息
- 全球观天下!PDF怎么编辑?PDF编辑方法大全
- TCP协议详解 一文读懂TCP协议段格式|每日热闻
- cr2是什么格式?CR2格式打开的方法步骤是什么?
- 世界观热点:【科普】什么是NAS?有什么好玩的功能?
- Cydia源是什么?Cydia源添加安装及更新步骤
- UAC功能是什么?关闭UAC功能的操作过程
- 男子称价值1.2万元AJ球鞋被调包 涉事物流:正沟通理赔
- 【干货】Linux管理文件和目录的命令
- 云存储是什么意思?云存储都有哪些用处?
- 牙克石市筑牢医保屏障助力乡村振兴
- 显卡硬件加速有什么用? 开启显卡硬件加速方法
- drivers是什么文件?drivers文件能不能删除?
- 如何卸载迈克菲软件?Mcafee卸载的方法
- PP加速器好用吗?PP加速器安装及使用步骤
- 连接打印机提示“打印处理器不存在”是什么原因?连接打印机提示打印处理器不存在解决步骤
- 变矩器是什么?变速齿轮机构的结构与工作原理
- win10系统怎么使用eZ Flash3刷BIOS?使用EZ Flash3刷BIOS步骤
- win10系统临时文件夹在哪?查找临时文件夹的步骤
- 如何输入avast注册码?avast软件介绍及激活码分享
- LanHelper工具有什么功能?LanHelper工具破解教程
- 笔记本内存条怎么安装?笔记本加内存条安装方法
- 注册表数据怎样进行修改?注册表编辑器打不开有什么解决办法?
- 出现0xc0000005错误是由什么原因造成的?c0000005异常代码解决方法
- Word中省略号怎么打?Word中省略号快捷键
- 耳机有杂音是什么原因造成的?耳机插上还是外放应该怎么办?
- 电脑时间不同步怎么办?电脑时间不同步的解决方法
- 《暗黑破坏神4》终极版预告 6月6日正式发售
- 环球焦点!三人被困雪地 男子用iPhone和大疆无人机成功自救
- 硅谷银行储户排长队取款:中国一公司已取回6亿元
- 苹果MR头显6月见!
- 天天热消息:外媒:《哥谭骑士》优化大幅度改进 卡顿完全没有了
- 郝旭蕾判刑_郝旭蕾
- 大获全胜 网飞获得6座奥斯卡
- 当前快看:《猎天使魔女:起源》IGN 9分:充满童趣和想象力
- 《遇见造物主》首发加入PS+ 4月4日发行
- 《光明旅者:破坏者》抢先体验推迟至秋季
- 昆汀最后一部电影片名曝光 今年秋季开拍_焦点快看
- 旅游零售板块3月14日跌0.25%,中国中免领跌,主力资金净流出8868.52万元_当前热议
- 16mn是什么材质价格多少_16mn是什么材质:环球播报
- COSPLAY图赏:国外小姐姐COS《死或生》玛丽萝丝 女仆装可爱又性感-微资讯
- “张译每剧嘎一个兄弟”上热搜:搭档总会壮烈牺牲
- SE区块链游戏《共生起源》首支预告 有上万角色
- 《最后生还者》第二季不会因游戏差评改剧情 尼尔不在乎那些差评:世界通讯
- 全球快资讯:PS官推“情人节送PS5告白”后续:白色情人节一起玩吗?
- 【环球时快讯】小米万兆路由器现在入手仅1699元:小米路由史上重大升级
- 【天天聚看点】13 代 i9+RTX40 系显卡,ROG 幻 16 翻转屏笔记本开售,miniLED 屏幕
- 焦点日报:美菱智能遥控茶吧机 24 小时保温,258元绝对值
- 【聚看点】冷知识:宠物猫平均寿命已增加到15年
- 《黑暗荣耀2》的蛇是真蛇!李莎拉演员:拍得很开心
- LG发布49GR85DC-B游戏显示器 32:9曲面屏
- 全球今热点:山东岚山区总工会开展心理健康服务活动
- 外网热议:《原神》是否拥有迄今为止最好的开放世界
- 《赛博朋克2077》高清重制MOD:纹理大提升!像新配了眼镜|今日报
- 《生化危机4:重制版》体验版bug:里昂一脚踢飞电锯人|世界热点
- 性价比逆天!i5-1235U迷你主机低至2258元-热资讯
- 博思云为借助亚马逊云科技赋能中国企业上云出海 连续5年营收翻番
- 半小时充电 20%,共享充电宝充电合理吗