前言
碰到了需要golang进行压缩文件夹的操作,在网上搜索到的压缩代码大多都一样,如下所示
// Zip 打包成zip文件
func Zip(filesDir string, zipPath string) {
// 预防:旧文件无法覆盖
os.RemoveAll(zipPath)
// 创建:zip文件
zipfile, _ := os.Create(zipPath)
defer zipfile.Close()
// 打开:zip文件
archive := zip.NewWriter(zipfile)
defer archive.Close()
// 遍历路径信息
filepath.Walk(filesDir, func(path string, info os.FileInfo, _ error) error {
// 如果是源路径,提前进行下一个遍历
if path == filesDir {
return nil
}
// 获取:文件头信息
header, _ := zip.FileInfoHeader(info)
header.Name = strings.TrimPrefix(path, filesDir+`\`)
// 判断:文件是不是文件夹
if info.IsDir() {
header.Name += `/`
} else {
// 设置:zip的文件压缩算法
header.Method = zip.Deflate
}
// 创建:压缩包头部信息
writer, _ := archive.CreateHeader(header)
if !info.IsDir() {
file, _ := os.Open(path)
defer file.Close()
io.Copy(writer, file)
}
return nil
})
}
运行后发现,他会将源文件的路径带入到压缩包内,并创建很多层路径文件夹,排查代码后发现,问题出在第24行
header.Name = strings.TrimPrefix(path, filesDir+`\`)
压缩代码
这一行的作用是将源文件的路径去掉前面压缩路径的部分,但是他用的符号是"\",而linux下的文件路径符号是"/",也就是该代码仅适用于win平台,进行改良后,能兼容win,linux双平台下的代码如下
// Zip 打包成zip文件
func Zip(filesDir string, zipPath string) {
sysType := runtime.GOOS
if sysType == "windows" {
// windows系统 统一路径符号为"\"
filesDir = strings.ReplaceAll(filesDir, "/", "\\")
}
// 预防:旧文件无法覆盖
os.RemoveAll(zipPath)
// 创建:zip文件
zipfile, _ := os.Create(zipPath)
defer zipfile.Close()
// 打开:zip文件
archive := zip.NewWriter(zipfile)
defer archive.Close()
// 遍历路径信息
filepath.Walk(filesDir, func(path string, info os.FileInfo, _ error) error {
// 如果是源路径,提前进行下一个遍历
if path == filesDir {
return nil
}
// 获取:文件头信息
header, _ := zip.FileInfoHeader(info)
if sysType == "windows" {
header.Name = strings.TrimPrefix(path, filesDir+`\`)
} else {
header.Name = strings.TrimPrefix(path, filesDir+`/`)
}
// 判断:文件是不是文件夹
if info.IsDir() {
header.Name += `/`
} else {
// 设置:zip的文件压缩算法
header.Method = zip.Deflate
}
// 创建:压缩包头部信息
writer, _ := archive.CreateHeader(header)
if !info.IsDir() {
file, _ := os.Open(path)
defer file.Close()
io.Copy(writer, file)
}
return nil
})
}
解压代码
另外附上解压文件的代码
// Unzip 解压文件
func Unzip(zipPath, dstDir string) error {
// 打开压缩包
reader, err := zip.OpenReader(zipPath)
if err != nil {
return err
}
defer reader.Close()
for _, file := range reader.File {
if err := unzipFile(file, dstDir); err != nil {
return err
}
}
return nil
}
func unzipFile(file *zip.File, dstDir string) error {
// 创建文件目录
filePath := path.Join(dstDir, file.Name)
if file.FileInfo().IsDir() {
if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
return err
}
return nil
}
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return err
}
// 读取文件内容
rc, err := file.Open()
if err != nil {
return err
}
defer rc.Close()
// 创建空文件
w, err := os.Create(filePath)
if err != nil {
return err
}
defer w.Close()
// 保存文件内容
_, err = io.Copy(w, rc)
return err
}