var fileContents stringif compression == noCompression {fileContents, i, err = readString(bs, i, int(uncompressedSize))if err != nil {return nil, 0, err}} else {end := i + int(compressedSize)if end > len(bs) {return nil, 0, errOverranBuffer}flateReader := flate.NewReader(bytes.NewReader(bs[i:end]))defer flateReader.Close()read, err := ioutil.ReadAll(flateReader)if err != nil {return nil, 0, err}fileContents = string(read)i = end}并返回填充好的结构体实例:
return &localFileHeader{signature: signature,version: version,bitFlag: bitFlag,compression: compression,lastModified: lastModified,crc32: crc32,compressedSize: compressedSize,uncompressedSize: uncompressedSize,fileName: fileName,extraField: extraField,fileContents: fileContents,}, i, nil}04 读取辅助函数现在我们只定义那些带有边界检查的读取辅助函数,使用 Go 的内置库来处理二进制编码 。
var errOverranBuffer = fmt.Errorf(&34;Overran buffer&34;)func readUint32(bs []byte, offset int) (uint32, int, error) {end := offset + 4if end > len(bs) {return 0, 0, errOverranBuffer}return binary.LittleEndian.Uint32(bs[offset:end]), end, nil}func readUint16(bs []byte, offset int) (uint16, int, error) {end := offset+2if end > len(bs) {return 0, 0, errOverranBuffer}return binary.LittleEndian.Uint16(bs[offset:end]), end, nil}并且基本上只对获取的字节和字符串进行边界检查 。
func readBytes(bs []byte, offset int, n int) ([]byte, int, error) {end := offset + nif end > len(bs) {return nil, 0, errOverranBuffer}return bs[offset:offset+n], end, nil}func readString(bs []byte, offset int, n int) (string, int, error) {read, end, err := readBytes(bs, offset, n)return string(read), end, err}05 MSDOS 时间我猜在创建 zip 时,MSDOS 时间格式很流行 。但它在今天并不流行,所以花了一些时间才最终用一些代码(模仿 C 语言)找到对该格式的解释[2] 。
func msdosTimeToGoTime(d uint16, t uint16) time.Time {seconds := int((t & 0x1F) * 2)minutes := int((t >> 5) & 0x3F)hours := int(t >> 11)day := int(d & 0x1F)month := time.Month((d >> 5) & 0x0F)year := int((d >> 9) & 0x7F) + 1980return time.Date(year, month, day, hours, minutes, seconds, 0, time.Local)}06 测试运行:
$ go build$ ./gozip test.zip2021-11-23 23:04:20 +0000 UTC hello.text Hello!这看起来不错!现在让我们尝试压缩多个文件 。
$ cat bye.textAu revoir!$ rm test.zip$ zip test.zip *.textadding: bye.text (stored 0%)adding: hello.text (stored 0%)$ ./gozip test.zip2021-11-24 03:40:00 +0000 UTC bye.text Au revoir!2021-11-23 23:04:20 +0000 UTC hello.text Hello!一切正常 。
07 总结实际上,还有许多标准需要处理(例如目录)和许多常见的扩展,本文没有涉及 。
文件末尾还有一些空间,这可能是 “central directory” 元数据,但我还没有深入研究 。如果你有兴趣可以查阅相关资料了解最后剩下的部分内容 。
原文链接:http://notes.eatonphil.com/implementing-zip-in-go-unzipping.html
参考资料[1]
这里: http://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
[2]
【zip文件怎么解压 zip文件怎么打开 vivo仿ios-1zip文件下载】对该格式的解释: http://groups.google.com/g/comp.os.msdos.programmer/c/ffAVUFN2NbA
- 原神飞行驾照第一关风柱没有了 原神飞行驾照第一关怎么考
- 抖音私信朋友列表怎么排列的 抖音私信朋友列表怎么删除
- 猕猴桃怎么催熟最快 4个方法!立即解决 猕猴桃怎么催熟 4种催熟猕猴桃的方法
- 乳胶头套怎么戴上去 橡胶头套怎么去味道
- dell笔记本电脑开不了机 dell笔记本电脑白屏怎么办
- 王者荣耀100强50强怎么弄的视频 王者荣耀100强50强怎么弄的
- 电脑怎么设置黑白打印 电脑怎么设置黑屏休眠状态
- 银行卡密码忘了可以委托他人办理吗 银行卡密码忘了怎么办 银行卡账户密码忘了
- 邮件服务器怎么用 邮件服务器使用的协议是什么
- 宠物怎么办理检疫证 宠物检疫证在哪里办理