go语言打包tar存档
功能介绍
- 可以多文件多文件夹混合打包
- 可以设置文件和文件夹黑白名单
- 可以打包成文件也可以打包成io.Reader类型数据
缺陷:
还是tar的特色,无法支持中文,所以中文打包会出现乱码,如果路径有中文,也无法打包文件,所以打包的文件或者文件夹尽量不要有中文
(有解决方法还请留言不吝指教,感谢感谢)
代码部分
// 打包目录下的所有文件和子文件,但不包括当前目录
func tarFolderToReader(
tarWriter *tar.Writer,
folderPath string,
rootDir bool,
fileWhitelist,
dirWhitelist,
fileBlacklist,
dirBlacklist []string,
) error {
err := filepath.Walk(folderPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == folderPath {
// 跳过根目录
return nil
}
for _, f1 := range fileWhitelist {
for _, f2 := range fileBlacklist {
if filepath.Clean(f1) == filepath.Clean(f2) {
return errors.New("文件的黑白名单冲突异常")
}
}
}
for _, d1 := range dirWhitelist {
for _, d2 := range dirBlacklist {
if filepath.Clean(d1) == filepath.Clean(d2) {
return errors.New("文件夹的黑白名单冲突异常")
}
}
}
// 如果文件白名单不为空,且是个文件
if len(fileWhitelist) != 0 && info.Mode().IsRegular() {
flagfile := false
//遍历白名单
for _, filew := range fileWhitelist {
// 如果匹配到白名单,就直接打包
if filepath.Clean(filew) == filepath.Clean(path) {
flagfile = true
goto end
} else if len(dirWhitelist) != 0 {
//如果没匹配到白名单,就看下所在的文件夹是不是被允许的
for _, dirw := range dirWhitelist {
if strings.HasPrefix(filepath.Clean(path), filepath.Clean(dirw)) {
//如果是文件夹白名单中的文件,就需要判断在不在文件黑名单中
if len(fileBlacklist) != 0 {
for _, filew := range fileBlacklist {
if filepath.Clean(filew) == filepath.Clean(path) {
goto end
}
}
}
if len(dirBlacklist) != 0 {
for _, dirw := range dirBlacklist {
if strings.HasPrefix(filepath.Clean(path), filepath.Clean(dirw)) {
goto end
}
}
}
flagfile = true
goto end
}
}
} else if len(fileBlacklist) != 0 {
return errors.New("文件的黑白名单冲突异常")
}
}
end:
if !flagfile {
return nil
}
} else if len(fileBlacklist) != 0 && info.Mode().IsRegular() {
flagfile := false
for _, filew := range fileBlacklist {
if filepath.Clean(filew) == filepath.Clean(path) {
flagfile = true
break
}
}
if len(dirBlacklist) != 0 {
for _, dirw := range dirBlacklist {
if strings.HasPrefix(filepath.Clean(path), filepath.Clean(dirw)) {
flagfile = true
break
}
}
}
if flagfile {
return nil
}
}
// 如果文件夹白名单存在,且是个文件夹
if len(dirWhitelist) != 0 && info.Mode().IsDir() {
flagdir := false
for _, dirw := range dirWhitelist {
// 判断是不是在白名单中
if filepath.Clean(dirw) == filepath.Clean(path) {
//是在白名单,则直接跳出通过
flagdir = true
goto end1
} else if strings.HasPrefix(filepath.Clean(path), filepath.Clean(dirw)) {
if len(dirBlacklist) != 0 {
for _, dirw := range dirBlacklist {
if filepath.Clean(dirw) == filepath.Clean(path) {
goto end1
}
}
}
flagdir = true
goto end1
}
}
end1:
if !flagdir {
return nil
}
} else if len(dirBlacklist) != 0 && info.Mode().IsDir() {
flagdir := false
for _, dirw := range dirBlacklist {
if filepath.Clean(dirw) == filepath.Clean(path) {
flagdir = true
break
}
}
if flagdir {
return nil
}
}
header, err := tar.FileInfoHeader(info, "")
if err != nil {
return err
}
if rootDir {
header.Name = filepath.FromSlash(path)
} else {
// 使用相对路径而不是绝对路径
relPath, err := filepath.Rel(folderPath, path)
if err != nil {
return err
}
header.Name = filepath.FromSlash(relPath)
}
// 对于Windows,在标头中将反斜杠转换为正斜杠。名称字段
if os.PathSeparator == '\\' {
header.Name = filepath.ToSlash(header.Name)
}
if info.IsDir() {
header.Name += "/"
}
header.Format = tar.FormatGNU
if err := tarWriter.WriteHeader(header); err != nil {
return err
}
if !info.Mode().IsRegular() {
return nil
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(tarWriter, file)
return err
})
if err != nil {
return err
}
return nil
}
上面的代码是功能部分,所依赖的库都是go的标准库
下面是使用方法
打包成文件的方式
func TestTarFiles(t *testing.T) {
// 定义输出的tar包的文件名
tarFileName := "a.tar"
// 创建输出文件
outputFile, err := os.Create(tarFileName)
if err != nil {
t.Fatal("无法创建输出文件:", err)
}
defer outputFile.Close()
tarWriter := tar.NewWriter(outputFile)
// 文件白名单
fileWhitelist := []string{
"Dockerfile",
"a.html",
"test/a.html",
}
// 文件夹白名单
dirWhitelist := []string{
"Dockerfile",
"a.html",
"test/a.html",
}
err = tarFolderToReader(
tarWriter,
".",
false,
fileWhitelist,
dirWhitelist,
nil,
nil,
)
if err != nil {
t.Fatal("打包文件失败:", err)
}
defer tarWriter.Close()
}
打包成io.Reader形式
func TestTarFiles(t *testing.T) {
buffer := new(bytes.Buffer)
tarWriter := tar.NewWriter(buffer)
// 文件白名单
fileWhitelist := []string{
"Dockerfile",
"a.html",
"test/a.html",
}
// 文件夹白名单
dirWhitelist := []string{
"Dockerfile",
"a.html",
"test/a.html",
}
err := tarFolderToReader(tarWriter,
".",
false,
fileWhitelist,
dirWhitelist,
nil,
nil,
)
if err != nil {
t.Fatal("打包文件失败:", err)
}
defer tarWriter.Close()
// 然后这里的buffer就是io.Reader形式
}
本文来自博客园,作者:厚礼蝎,转载请注明原文链接:https://www.cnblogs.com/guangdelw/p/17571861.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!