golang tar打包文件或文件夹,包含中文路径问题处理

Grassto · · 1526 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

最近主要处理了golang有关**tar包**打包与解包相关的事务,发现当存在中文路径的时候,会出现如下问题: ###### 需要打包的文件夹:E:\测试 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190604202201419.gif) ##### 打包后的tar包却变成了这样:![在这里插入图片描述](https://img-blog.csdnimg.cn/20190604201807777.gif) 无缘无故多了个PaxHeaders.0的文件夹,中文文件夹和中文文件的名字还没了(郁闷!) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190604202415851.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Rpc01pc1ByZXM=,size_16,color_FFFFFF,t_70) 仔细一想,不对啊这,难道是打包代码写的有问题?但是用英文路径都没问题,之后发现:**tar包的默认格式,不支持中文路径,手动改成使用GNU格式即可。** ```go hdr.Format = tar.FormatGNU ``` 具体代码如下: ```go package tar import ( "archive/tar" "errors" "fmt" "io" "io/ioutil" "log" "os" "path" "path/filepath" ) func tt2() { err := Tar2("E:/测试", "F:/GoTest/commonTest/tar/hw", false) if err != nil { log.Fatal(err) } fmt.Println("打包完成") } // 将文件或目录打包成 .tar 文件 // src 是要打包的文件或目录的路径 // dstTar 是要生成的 .tar 文件的路径 // failIfExist 标记如果 dstTar 文件存在,是否放弃打包,如果否,则会覆盖已存在的文件 func Tar2(src string, dstTar string, failIfExist bool) (err error) { // 清理路径字符串 src = path.Clean(src) // 判断要打包的文件或目录是否存在 if !Exists(src) { return errors.New("要打包的文件或目录不存在:" + src) } // 判断目标文件是否存在 if FileExists(dstTar) { if failIfExist { // 不覆盖已存在的文件 return errors.New("目标文件已经存在:" + dstTar) } else { // 覆盖已存在的文件 if er := os.Remove(dstTar); er != nil { return er } } } // 创建空的目标文件 fw, er := os.Create(dstTar) if er != nil { return er } defer fw.Close() // 创建 tar.Writer,执行打包操作 tw := tar.NewWriter(fw) defer func() { // 这里要判断 tw 是否关闭成功,如果关闭失败,则 .tar 文件可能不完整 if er := tw.Close(); er != nil { err = er } }() // 获取文件或目录信息 fi, er := os.Stat(src) if er != nil { return er } // 获取要打包的文件或目录的所在位置和名称 // srcBase, srcRelative := path.Split(filepath.Clean(src)) srcBase := filepath.Dir(filepath.Clean(src)) srcRelative := filepath.Base(filepath.Clean(src)) // 开始打包 if fi.IsDir() { tarDir2(srcBase, srcRelative, tw, fi) } else { tarFile2(srcBase, srcRelative, tw, fi) } return nil } // 因为要执行遍历操作,所以要单独创建一个函数 func tarDir2(srcBase, srcRelative string, tw *tar.Writer, fi os.FileInfo) (err error) { // 获取完整路径 srcFull := srcBase + srcRelative // 在结尾添加 "/" last := len(srcRelative) - 1 if srcRelative[last] != os.PathSeparator { srcRelative += string(os.PathSeparator) } // 获取 srcFull 下的文件或子目录列表 fis, er := ioutil.ReadDir(srcFull) if er != nil { return er } // 开始遍历 for _, fi := range fis { if fi.IsDir() { tarDir2(srcBase, srcRelative+fi.Name(), tw, fi) } else { tarFile2(srcBase, srcRelative+fi.Name(), tw, fi) } } // 写入目录信息 if len(srcRelative) > 0 { hdr, er := tar.FileInfoHeader(fi, "") if er != nil { return er } hdr.Name = srcRelative hdr.Format = tar.FormatGNU if er = tw.WriteHeader(hdr); er != nil { return er } } return nil } // 因为要在 defer 中关闭文件,所以要单独创建一个函数 func tarFile2(srcBase, srcRelative string, tw *tar.Writer, fi os.FileInfo) (err error) { // 获取完整路径 srcFull := srcBase + srcRelative // 写入文件信息 hdr, er := tar.FileInfoHeader(fi, "") if er != nil { return er } hdr.Name = srcRelative hdr.Format = tar.FormatGNU if er = tw.WriteHeader(hdr); er != nil { return er } // 打开要打包的文件,准备读取 fr, er := os.Open(srcFull) if er != nil { return er } defer fr.Close() // 将文件数据写入 tw 中 if _, er = io.Copy(tw, fr); er != nil { return er } return nil } ```

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1526 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传