Golang实现压缩文件时避免在存档中创建文件夹的方法

Golang实现压缩文件时避免在存档中创建文件夹的方法 大家好,

我是Go语言的新手,正在尝试编写一个函数来获取文件列表并将它们压缩打包。今天搜索了很久,虽然可以轻松地归档文件,但归档文件内部还会创建一个文件夹(出于某些不便说明的原因,这样行不通)。我基本上需要将一个目录中的所有文件压缩,不包含任何文件夹结构,仅此而已。以下是我目前正在使用的代码:

package main

import (
"archive/zip"
"os"
"path/filepath"
"strings"
"io"
)

func zipit(source, target string) error {
	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	info, err := os.Stat(source)
	if err != nil {
		return nil
	}

	var baseDir string
	if info.IsDir() {
		baseDir = filepath.Base(source)
	}

	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		if baseDir != "" {
			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
		}

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := archive.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	})

	return err
}

func main() {
	zipit("output/","ABG_Gather_Data.zip")
}

更多关于Golang实现压缩文件时避免在存档中创建文件夹的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

我会稍后尝试一下……不过老兄,我也是这种情况。需求收集时说明这个zip文件的处理无法处理文件夹……这算什么?

更多关于Golang实现压缩文件时避免在存档中创建文件夹的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


要实现你需要的功能,只需从所有名称的开头去除文件夹部分。

func zipit(source, target string) error {
	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	base := filepath.Base(source)

	err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if info.IsDir() {
			if source == path {
				return nil
			}
			path += "/"
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		header.Name = path[len(base)+1:]
		header.Method = zip.Deflate

		writer, err := archive.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	})
	if err != nil {
		return err
	}
	if err = archive.Flush(); err != nil {
		return err
	}
	return nil
}

注意我改进了错误处理:你之前没有捕获filepath.Walk的错误,而且"defer Close()"也会让错误(可能发生在实际将缓冲文件写入磁盘时)消失。为了解决这个问题,我使用了Flush()。

最后,请装饰你的错误信息。不要直接返回err,而是返回fmt.Errorf("无法<写下你正在尝试的操作>:%v", err)(例如’创建zip头’、‘打开要包含在存档中的文件’、‘将文件复制到存档中’)。

个人说明:我讨厌那些不创建文件夹的zip文件。

以下是修改后的代码,它会在压缩文件中直接包含文件而不创建文件夹结构:

package main

import (
	"archive/zip"
	"io"
	"os"
	"path/filepath"
)

func zipFiles(sourceDir, target string) error {
	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	err = filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 跳过目录,只处理文件
		if info.IsDir() {
			return nil
		}

		// 使用文件名作为压缩文件中的路径,不包含目录结构
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		header.Name = filepath.Base(path)
		header.Method = zip.Deflate

		writer, err := archive.CreateHeader(header)
		if err != nil {
			return err
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()

		_, err = io.Copy(writer, file)
		return err
	})

	return err
}

func main() {
	err := zipFiles("output/", "ABG_Gather_Data.zip")
	if err != nil {
		panic(err)
	}
}

主要修改点:

  1. 移除了 baseDir 相关逻辑
  2. filepath.Walk 的回调函数中直接跳过目录(if info.IsDir() { return nil }
  3. 设置 header.Name = filepath.Base(path),只使用文件名而不包含路径
  4. 简化了目录处理逻辑

这样生成的ZIP文件中将只包含文件名,不会创建任何文件夹结构。例如,如果 output/ 目录下有 file1.txtfile2.jpg,压缩包中将直接包含这两个文件,不会出现 output/ 文件夹。

回到顶部