原文:https://blog.csdn.net/xiaobing1994/article/details/78367035
zip文件格式
说明
本人根据自己的学习过程,适当理解,并作下笔记,以便查阅。这里暂不包含zip64部分。
整体结构
简单归纳总结下,zip文件格式由文件数据区、中央目录结构,中央目录结束标志组成。其中中央目录结束节又有一个字段保存了中央目录结构的偏移。整体结构如下图
分区描述
中央目录结束标志
中央目录结束标志一般位于文件的末尾。由于它也有字段指向了中央目录开始处的偏移, 所以把它放在最前面描述。它被用来标识中央目录结束。可以通过读取它来找到中央目录并解析整个文件结构。该结构具体如下:
struct EndLocator
{
ui32 signature; //目录结束标记,固定值0x06054b50)
ui16 elDiskNumber; //当前磁盘编号
ui16 elStartDiskNumber; //中央目录开始位置的磁盘编号
ui16 elEntriesOnDisk; //该磁盘上所记录的核心目录数量
ui16 elEntriesInDirectory; //中央目录结构总数
ui32 elDirectorySize; //中央目录的大小
ui32 elDirectoryOffset; //中央目录开始位置相对于文件头的偏移
ui16 elCommentLen; // 注释长度
char *elComment; // 注释内容
};
中央目录结构
中央目录结构位于文件数据区后,它用来保存所有文件的路径信息,和对应文件数据结构区在文件中的偏移。该结构具体如下:
struct DirEntry
{
ui32 signature; // 中央目录文件header标识(0x02014b50)
ui16 deVersionMadeBy; // 压缩所用的pkware版本
ui16 deVersionToExtract; // 解压所需pkware的最低版本
ui16 deFlags; // 通用位标记
ui16 deCompression; // 压缩方法
ui16 deFileTime; // 文件最后修改时间
ui16 deFileDate; // 文件最后修改日期
ui32 deCrc; // CRC-32校验码
ui32 deCompressedSize; // 压缩后的大小
ui32 deUncompressedSize; // 未压缩的大小
ui16 deFileNameLength; // 文件名长度
ui16 deExtraFieldLength; // 扩展域长度
ui16 deFileCommentLength; // 文件注释长度
ui16 deDiskNumberStart; // 文件开始位置的磁盘编号
ui16 deInternalAttributes; // 内部文件属性
ui32 deExternalAttributes; // 外部文件属性
ui32 deHeaderOffset; // 本地文件头的相对位移
char *deFileName; // 目录文件名
char *deExtraField; // 扩展域
char *deFileComment; // 文件注释内容
};
中央目录结构区是由中央目录结构的数组组成,这个结构只有目录文件名,扩展域,文件注释内容长度是不定的,并且可以在这个结构中获取它的长度,那么通过此就可以遍历出所有的文件。设当前中央目录结构偏移为current_offset,下个中央目录结构偏移为next_offset,则计算公式为:
next_offset = current_offset + sizeofDirEntry) – 3*sizeofchar*) + deFileNameLength + deExtraFieldLength + deFileCommentLength;
其中CRC32校验码为对应的文件压缩数据的CRC32的校验码,如对应文件的数据压缩数据的CRC32与这里的值不同,则数据损坏。
通过中央目录结构的deHeaderOffset字段可以直接获取到对应文件的文件数据区结构的文件偏移,就可以直接获取到对应文件的压缩数据了。
文件数据区
文件数据区是保存所有压缩文件数据的区,它位于文件头,并由压缩数据结构的数组组成。其结构如下:
struct Record
{
ui32 signature; // 文件头标识,值固定0x04034b50)
ui16 frVersion; // 解压文件所需 pkware最低版本
ui16 frFlags; // 通用比特标志位置比特0位=加密)
ui16 frCompression; // 压缩方式
ui16 frFileTime; // 文件最后修改时间
ui16 frFileDate; //文件最后修改日期
ui32 frCrc; // CRC-32校验码
ui32 frCompressedSize; // 压缩后的大小
ui32 frUncompressedSize; // 未压缩的大小
ui16 frFileNameLength; // 文件名长度
ui16 frExtraFieldLength; // 扩展区长度
char* frFileName; // 文件名
char* frExtraField; // 扩展区
char* frData; // 压缩数据
};
这里的压缩方式frCompression有如下取值:
0 – The file is stored no compression)
1 – The file is Shrunk
2 – The file is Reduced with compression factor 1
3 – The file is Reduced with compression factor 2
4 – The file is Reduced with compression factor 3
5 – The file is Reduced with compression factor 4
6 – The file is Imploded
7 – Reserved for Tokenizing compression algorithm
8 – The file is Deflated
9 – Enhanced Deflating using Deflate64tm)
10 – PKWARE Data Compression Library Imploding
11 – Reserved by PKWARE
12 – File is compressed using BZIP2 algorithm
通过中央目录结构就可以找到文件数据结构,通过文件数据结构获取到压缩数据结构,并通过此结构可以获取到压缩的数据和使用的算法,并可以根据此解压出对应的数据。
crc32
crc32即循环冗余校验,一般用于校验数据是否正确。其实现方式参考http://blog.csdn.net/lickylin/article/details/7857586
总结
zip文件结构比较清晰,可以从位于文件尾的中央文件目录结束区入手,获取到中央目录结构的偏移地址,再遍历中央目录获取到所有的文件,并通过文件数据结构获取到文件数据,数据是否损坏可通过crc32进行校验。