Zip 压缩文件或目录 @params dst io.Writer 压缩文件可写流 @params src string 待压缩源文件/目录路径
(dst io.Writer, src string)
| 246 | // @params dst io.Writer 压缩文件可写流 |
| 247 | // @params src string 待压缩源文件/目录路径 |
| 248 | func Zip(dst io.Writer, src string) error { |
| 249 | // 强转一下路径 |
| 250 | src = filepath.Clean(src) |
| 251 | // 提取最后一个文件或目录的名称 |
| 252 | baseFile := filepath.Base(src) |
| 253 | // 判断src是否存在 |
| 254 | _, err := os.Stat(src) |
| 255 | if err != nil { |
| 256 | return err |
| 257 | } |
| 258 | |
| 259 | // 通文件流句柄创建一个ZIP压缩包 |
| 260 | zw := zip.NewWriter(dst) |
| 261 | // 延迟关闭这个压缩包 |
| 262 | defer zw.Close() |
| 263 | |
| 264 | // 通过filepath封装的Walk来递归处理源路径到压缩文件中 |
| 265 | return filepath.Walk(src, func(path string, info fs.FileInfo, err error) error { |
| 266 | // 是否存在异常 |
| 267 | if err != nil { |
| 268 | return err |
| 269 | } |
| 270 | |
| 271 | // 通过原始文件头信息,创建zip文件头信息 |
| 272 | zfh, err := zip.FileInfoHeader(info) |
| 273 | if err != nil { |
| 274 | return err |
| 275 | } |
| 276 | |
| 277 | // 赋值默认的压缩方法,否则不压缩 |
| 278 | zfh.Method = zip.Deflate |
| 279 | |
| 280 | // 移除绝对路径 |
| 281 | tmpPath := path |
| 282 | index := strings.Index(tmpPath, baseFile) |
| 283 | if index > -1 { |
| 284 | tmpPath = tmpPath[index:] |
| 285 | } |
| 286 | // 替换文件名,并且去除前后 "\" 或 "/" |
| 287 | tmpPath = strings.Trim(tmpPath, string(filepath.Separator)) |
| 288 | // 替换一下分隔符,zip不支持 "\\" |
| 289 | zfh.Name = strings.ReplaceAll(tmpPath, "\\", "/") |
| 290 | // 目录需要拼上一个 "/" ,否则会出现一个和目录一样的文件在压缩包中 |
| 291 | if info.IsDir() { |
| 292 | zfh.Name += "/" |
| 293 | } |
| 294 | |
| 295 | // 写入文件头信息,并返回一个ZIP文件写入句柄 |
| 296 | zfw, err := zw.CreateHeader(zfh) |
| 297 | if err != nil { |
| 298 | return err |
| 299 | } |
| 300 | |
| 301 | // 仅在他是标准文件时进行文件内容写入 |
| 302 | if zfh.Mode().IsRegular() { |
| 303 | // 打开要压缩的文件 |
| 304 | sfr, err := os.Open(path) |
| 305 | if err != nil { |