首页后端开发GOgolang封装tar打包解包之二

golang封装tar打包解包之二

时间2023-12-07 10:15:03发布访客分类GO浏览1258
导读:好久没上来这里写专栏了,发现上一篇有关tar打包解包还留着一个坑。这里补上。本文介绍下通过os/exec调用shell命令,直接调用系统的tar命令进行打包。方案二、通过调用系统的tar命令基本思路是先拼接tar打包和解包的命令,然后调用o...

好久没上来这里写专栏了,发现上一篇有关tar打包解包还留着一个坑。这里补上。

本文介绍下通过os/exec调用shell命令,直接调用系统的tar命令进行打包。

方案二、通过调用系统的tar命令

基本思路是先拼接tar打包和解包的命令,然后调用os/exec包的CommandContext方法执行shell命令。这里要求操作系统中需要有tar命令。

公共方法的定义

这里定义一个结构体,对日志的读取、shell脚本的执行做了封装。当然如果需要执行其他shell命令,直接给exec方法传入具体命令也是可以的。

type TgzLinuxPacker struct {

   ctx        context.Context    // context上下文,监听上层的退出信号
   cancel     context.CancelFunc // context的取消函数
   wg         sync.WaitGroup
   outputList []string // 命令的输出
}


func NewTgzLinuxPacker(ctx context.Context) *TgzLinuxPacker {
    
   subCtx, cancel := context.WithCancel(ctx)
   return &
TgzLinuxPacker{

      ctx:        subCtx,
      cancel:     cancel,
      wg:         sync.WaitGroup{
}
,
      outputList: make([]string, 0),
   }

}


// 从标准输出、错误输出读取内容
func (tlp *TgzLinuxPacker) readLog(stdReader io.Reader) {

   defer tlp.wg.Done()
   reader := bufio.NewReader(stdReader)
   for {

      select {

      case -tlp.ctx.Done():
         return
      default:
         readString, err := reader.ReadString('\n')
         if err != nil || err == io.EOF {

            return
         }

         line := strings.Trim(readString, "\n")
         tlp.outputList = append(tlp.outputList, line)
      }

   }

}


// 命令执行的封装
func (tlp *TgzLinuxPacker) exec(cmdStr string) error {

   // 方法退出时触发cancel方法的调用,通知readLog和shell子进程退出
   defer tlp.cancel()
   c := exec.CommandContext(tlp.ctx, "/bin/bash", "-c", cmdStr)
   // get stdout stderr pipe
   stdout, err := c.StdoutPipe()
   if err != nil {

      return err
   }

   stderr, err := c.StderrPipe()
   if err != nil {

      return err
   }

   // read stdout stderr
   tlp.wg.Add(2)
   go tlp.readLog(stdout)
   go tlp.readLog(stderr)
   // 开始执行
   err = c.Start()
   if err != nil {

      return err
   }

   // 等待readLog退出
   tlp.wg.Wait()
   // 这里调用一次wait,获取shell进程的退出码
   err = c.Wait()
   if err != nil {

      return errors.New(strings.Join(tlp.outputList, "\n") + err.Error())
   }

   if !c.ProcessState.Success() {

      return errors.New("返回码:" + strconv.Itoa(c.ProcessState.ExitCode()) + "\n" + strings.Join(tlp.outputList, "\n"))
   }

   return nil
}

压缩打包

有了执行shell命令的方法后,我们要进行打包的工作,那就相当简单了,直接拼接命令行即可

func (tlp *TgzLinuxPacker) Pack(sourceFullPath string, tarFileName string) error {

   // e.g: tar -zcf test.tar.gz -C /tmp/ test
   cmdStr := "tar -zcf " + tarFileName + " -C " + filepath.Dir(sourceFullPath) + " " + filepath.Base(sourceFullPath)
   return tlp.exec(cmdStr)
}

解压

同压缩打包,值需要拼接解压命令即可

func (tlp *TgzLinuxPacker) Unpack(tarFileName string, dstDir string) error {

   // e.g: tar -zxf /tmp/test.tar.gz -C /tmp/
   cmdStr := "tar -zxf " + tarFileName + " -C " + dstDir
   return tlp.exec(cmdStr)
}
    

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: golang封装tar打包解包之二
本文地址: https://pptw.com/jishu/571818.html
Go高级之Gin框架和Mongodb数据库的联动 呜呜呜我要拿Go赢他~ 入门,Go的最简单的 Web 服务器!

游客 回复需填写必要信息