开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 16 天,点击查看活动详情
Zip
ZIP 是一种常见的文件压缩格式,其压缩原理主要是通过将多个文件或目录组成一个归档文件,再对这个归档文件进行压缩来实现的。
在 ZIP 中,归档文件中的每个文件都被压缩成一个单独的数据块,这个数据块中包含了该文件的数据以及该文件的元数据(如文件名、文件修改时间、文件权限等)。归档文件中还包含了一个目录,记录了归档文件中包含的每个文件的元数据。
ZIP 中使用的压缩算法通常是 DEFLATE 算法,它是一种基于哈夫曼编码和LZ77算法的无损压缩算法。DEFLATE 算法可以通过对输入数据进行匹配和替换来实现数据的压缩,从而减小归档文件的大小。在 ZIP 中,DEFLATE 算法通常是在每个文件的数据块上独立应用的,这样可以保证在解压缩时,只需要解压缩需要的文件,而不需要解压缩整个归档文件。
总之,ZIP 的压缩原理主要是将多个文件或目录组成一个归档文件,并对归档文件中的每个文件进行压缩,从而减小文件的大小。这样可以更方便地在网络上传输或在存储设备上存储和管理文件。
压缩
// Zip 把路径的文件夹zip压缩
func Zip(path string) error {
// 1. Create a ZIP file and zip.Writer
f, err := os.Create(path + ".zip")
if err != nil {
return err
}
defer f.Close()
writer := zip.NewWriter(f)
defer writer.Close()
// 2. Go through all the files of the source
return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 3. Create a local file header
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// set compression
header.Method = zip.Deflate
// 4. Set relative path of a file as the header name
header.Name, err = filepath.Rel(filepath.Dir(path), path)
if err != nil {
return err
}
if info.IsDir() {
header.Name += "/"
}
// 5. Create writer for the file header and save content of the file
headerWriter, err := writer.CreateHeader(header)
if err != nil {
return err
}
if info.IsDir() {
return nil
}
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(headerWriter, f)
return err
})
}
解压缩
// 原地解压缩
func UnZip(src, dst string) (err error) {
// 打开压缩文件,这个 zip 包有个方便的 ReadCloser 类型
// 这个里面有个方便的 OpenReader 函数,可以比 tar 的时候省去一个打开文件的步骤
zr, err := zip.OpenReader(src)
defer zr.Close()
if err != nil {
return
}
// 如果解压后不是放在当前目录就按照保存目录去创建目录
//if dst != "" {
// if err := os.MkdirAll(dst, 0755); err != nil {
// return err
// }
//}
// 遍历 zr ,将文件写入到磁盘
for _, file := range zr.File {
path := filepath.Join(dst, file.Name)
// 如果是目录,就创建目录
if file.FileInfo().IsDir() {
if err := os.MkdirAll(path, file.Mode()); err != nil {
return err
}
// 因为是目录,跳过当前循环,因为后面都是文件的处理
continue
}
// 获取到 Reader
fr, err := file.Open()
if err != nil {
return err
}
// 创建要写出的文件对应的 Write
fw, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
//n, err := io.Copy(fw, fr)
if err != nil {
return err
}
// 将解压的结果输出
//fmt.Printf("成功解压 %s ,共写入了 %d 个字符的数据\n", path, n)
// 因为是在循环中,无法使用 defer ,直接放在最后
// 不过这样也有问题,当出现 err 的时候就不会执行这个了,
// 可以把它单独放在一个函数中,这里是个实验,就这样了
fw.Close()
fr.Close()
}
return nil
}
注意事项
用压缩代码压缩和解压没什么异常,但是windows电脑压缩的zip,解压后中文文件名就乱码了,需要加一步编码的控制。