用户工具

站点工具


踩坑记录:20230822解压缩zip文件报错

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
踩坑记录:20230822解压缩zip文件报错 [2023/08/22 20:19] – 创建 MNBVC项目组踩坑记录:20230822解压缩zip文件报错 [2023/08/22 22:16] (当前版本) MNBVC项目组
行 12: 行 12:
 我在源代码中定位了报错的地方,经过了一系列的zip解压缩格式的原理的了解和对zip解压代码的测试。 我在源代码中定位了报错的地方,经过了一系列的zip解压缩格式的原理的了解和对zip解压代码的测试。
  
-在zip中,PK\x03\x04是文件的前四个字节,是代表他是个zip压缩文件的magci number。+在zip中,PK\x03\x04是文件的前四个字节,是代表他是个zip压缩文件的magci number,以及文件头部的一些信息,但这里没用到
  
-PK\x05\x06到文件结尾的22个字节是zip文件尾部的magic number,后面的18个字节是zip文件的一些相关信息,主要放着zip包里的文件个数,central directory相对文件起始处的偏移量,central directory的长度这些信息。+PK\x05\x06到文件结尾的总共22个字节是zip文件尾部的magic number,后面的18个字节是zip文件的一些相关信息,主要放着zip包里的文件个数,central directory相对文件起始处的偏移量,central directory的长度这些信息。
  
-其中central directory是一个目录样的结构,一般在文件尾部那22个字节的前面,每一个文件/文件夹的条目都以PK\x01\x02这个魔数来开头,如果不一致就会发生我们遇到的Bad magic number for central directory的报错,其中每一个条目长度是46个字节,包含了文件/文件夹的一些基础信息,比如压缩前压缩后的长度,创建时间,在zip包中的位置等信息,紧跟在每一个条目后面的就是文件名,文件名的长度也在前面条目的信息里。zipfile这个库会根据这些东西来找到文件的基础信息,用来解压。+其中central directory是一个目录样的结构,存放里面压缩的文件或者文件夹信息,一般在文件尾部那22个字节的前面,每一个文件/文件夹的条目都以PK\x01\x02这个魔数来开头,如果不一致就会发生我们遇到的Bad magic number for central directory的报错,其中每一个条目长度包括魔数是46个字节,包含了文件/文件夹的一些基础信息,比如压缩前压缩后的长度,创建时间,在zip包中的位置等信息,紧跟在每一个条目后面的就是文件名,文件名的长度也在前面条目的信息里。zipfile这个库会根据这些东西来找到文件的基础信息,用来解压。
  
-在我们测试的压缩包中,存在两个central directory和后面的PK\x05\x06分magic number的信息,其中第二个PK\x05\x06也就是文件末尾部分,给出的是不正确的相关信息,central directory的位置和长度均不正确,出现的第二个central directory也有一些问题,他出现了已经被删除的文件的信息,其他相关信息似乎也和第一个central directory不一致。+在我们测试的压缩包中,存在一个zip文件内出现了两个central directory和后面的PK\x05\x06数据,其中第二个PK\x05\x06也就是文件末尾部分,给出的是不正确的相关信息,central directory的位置和长度均不正确,所以unzip和python的zipfile库用的这个信息获取了错误的entral directory的位置,出现的第二个central directory也有一些问题,他出现了已经被删除的文件的信息,其他相关信息似乎也和第一个central directory不一致。
  
 我将第二个central directory和后面的尾部信息舍去,只留下第一个,就可以正常解压了。 我将第二个central directory和后面的尾部信息舍去,只留下第一个,就可以正常解压了。
 +
 +猜测可能是在压缩包之内删除文件遇到了什么奇怪的缓存不一致之类的问题,导致最后那些表的信息被混乱重复的第二次追加到zip文件的尾部。
 +
 +正常的解压代码是这样的:
 +
 +
 +  with zipfile.ZipFile(file, 'r') as zip:
 +      zip.extractall('/your/path')
 +
 +
 +我们只需要修改成:
 +
 +
 +  import io
 +  fp = open(file_path, 'rb')
 +  #读出zip文件的数据,排除掉尾部数据
 +  data = fp.read()[:-22]
 +  fp.close()
 +  #找到从右向左的看,第二个尾部数据
 +  index = data.rfind(b'PK\005\006') + 22
 +  #只剩下真正的压缩包数据
 +  data = io.BytesIO(data[:index])
 +  #zipfile可以用byte io来读取数据,和上面的效果一样
 +  with zipfile.ZipFile(data, 'r') as zip:
 +      zip.extractall('/your/path')
  
  
踩坑记录/20230822解压缩zip文件报错.1692706796.txt.gz · 最后更改: 2023/08/22 20:19 由 MNBVC项目组