zip格式调研
背景
想用下zip的无压缩打包,故调研下下zip格式协议。
调研结论
- go、php、c、c++、lua均有开源库可已处理zip包,使用方式很简单。
- 不压缩只打包zip可以支持range获取数据,但是需要三次位移才能完成。先读取尾部22个字节,获取到目录结束标记。再通过目录结束标记中的偏移量等信息下载中心目录信息,从中心目录信息中获取到每个文件的偏移量信息和文件名信息。再通过对应文件的偏移量信息读取该文件的数据段,再通过数据段的local file header定位获取到该文件的数据。
- zip结构主要由 文件数据段 + 中心目录段 + 结尾目录段 这三部分构成,除了结尾目录端是固定22字节(无注释情况下)外,其他两个段都是变长的,影响中心目录段长度的是文件数和各文件的文件名长度。
- zip结尾目录段的注释部分可以自定义(ZIP file comment length + ZIP file comment),通过zip -z ./test.zip 就可以给zip文件添加注释。
zip打包格式说明
[local file header + file data + data descriptor]{1,n} + [central directory] + [end of central directory record] [文件头+文件数据+数据描述符]{可重复n次}+核心目录信息+目录结束标识
主要就是[local file header + file data]。
记录了压缩文件的目录信息,在这个数据区中每一条纪录对应在压缩源文件数据区中的一条数据。
每一条纪录对应信息。
range获取数据方式:
核心目录结尾段:
先读取结尾22个字节获取到zip文件的End of central directory record,从End of central directory record获取到核心目录的偏移量、核心目录结构总数、核心目录大小。
核心目录段:
再读取完整核心目录,根据核心目录结构总数遍历每个结构,根据文件名后缀取图片或者视频的偏移量(relative offset of local header)、数据长度(compressed size)、文件名长度(file name length)、扩展预长度(extra field length)。
数据段:
然后根据偏移量+30+文件名长度+扩展预长度为偏移量,数据长度为长度获取数据。
也就是一个文件需要读取三次获取到所需要的数据。这种方式需要打包zip版本固定,否则可能改变导致不兼容。
各语言支持
- php: http://php.net/manual/zh/ref.zip.php
- c/c++: https://libzip.org/documentation/
- lua: http://luazip.luaforge.net/manual.html#introduction
- golang: import “archive/zip”
参考资料
- https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.2.0.txt
- http://blog.csdn.net/a_flying_bird/article/details/46625873
- http://blog.csdn.net/a200710716/article/details/51644421
- http://blog.csdn.net/delphiwcdj/article/details/39717617