zip文件格式

原文: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进行校验。
 

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注