golang压缩和解压缩zip文件
一个简单例子说明如何使用golang提供的archive/zip包实现zip文件的压缩和解压缩。
压缩
提供两个参数:
其中输入源文件可以是一个文件,也可以好似一个目录,如果是目录那么目录下的所有文件都会被压缩到输出。
当然这个函数很容易被扩展成支持多个输入源文件/目录的情况。
// srcFile could be a single file or a directory
func Zip(srcFile string, destZip string) error {
zipfile, err := os.Create(destZip)
if err != nil {
return err
}
defer zipfile.Close()
archive := zip.NewWriter(zipfile)
defer archive.Close()
filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = strings.TrimPrefix(path, filepath.Dir(srcFile) + "/")
// header.Name = path
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if ! info.IsDir() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
}
return err
})
return err
}
解压缩
也有提供两个参数:
func Unzip(zipFile string, destDir string) error {
zipReader, err := zip.OpenReader(zipFile)
if err != nil {
return err
}
defer zipReader.Close()
for _, f := range zipReader.File {
fpath := filepath.Join(destDir, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(fpath, os.ModePerm)
} else {
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return err
}
inFile, err := f.Open()
if err != nil {
return err
}
defer inFile.Close()
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer outFile.Close()
_, err = io.Copy(outFile, inFile)
if err != nil {
return err
}
}
}
return nil
}
问题来了
fpath := filepath.Join(destDir, f.Name)后 fpath为 D:\UnzipFile\D:\test\1.txt
header.Name += "/" 这句代码直接使用 / 不太好
解决办法
1.修改zip函数,如果传入的是文件夹,保存的路径层级去掉文件夹路径。如果传入的是文件,修改Unzip函数处理 f.name 去掉盘符冒号反斜杠 ,如 D:\
2. 将 “/” 替换为
string(os.PathSeparator)
修改后的代码
压缩文件:
// srcFile could be a single file or a directory
func Zip(srcFile string, destZip string) error {
zipfile, err := os.Create(destZip)
if err != nil {
return err
}
defer zipfile.Close()
archive := zip.NewWriter(zipfile)
defer archive.Close()
filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 如果是源路径(文件夹),提前进行下一个遍历
if path == srcFile {
if info.IsDir() {
return nil
}
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
//header.Name = path
//header.Name = strings.TrimPrefix(path, filepath.Dir(srcFile) + "/")
header.Name = strings.TrimPrefix(path, srcFile + string(os.PathSeparator))
if info.IsDir() {
header.Name += string(os.PathSeparator)
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if ! info.IsDir() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
}
return err
})
return err
}
解压文件:
func Unzip(zipFile string, destDir string) error {
zipReader, err := zip.OpenReader(zipFile)
if err != nil {
return err
}
defer zipReader.Close()
for _, f := range zipReader.File {
fpath := ""
name := f.Name
if find := strings.Contains(name,":"); find {
name = name[strings.Index(name,":") + 2 : len(name) ]
fpath = filepath.Join(destDir, name)
}else{
fpath = filepath.Join(destDir, name)
}
if f.FileInfo().IsDir() {
os.MkdirAll(fpath, os.ModePerm)
} else {
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return err
}
inFile, err := f.Open()
if err != nil {
return err
}
defer inFile.Close()
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer outFile.Close()
_, err = io.Copy(outFile, inFile)
if err != nil {
return err
}
}
}
return nil
}
其他中文编码问题:
Go语言zip解压._JieLinDee的专栏-CSDN博客package mainimport ("archive/zip""fmt""io""os")func main() {r, err := zip.OpenReader(`server_update_20151020.zip`)if err != nil {fmt.Println(err)return}for _, k := range r.Rhttps://blog.csdn.net/fyxichen/article/details/49273883