golang封装tar打包解包之二

2023-11-07 20:23:12 浏览数 (1)

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

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

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

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

公共方法的定义

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

代码语言:javascript复制
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命令的方法后,我们要进行打包的工作,那就相当简单了,直接拼接命令行即可

代码语言:javascript复制
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)
}

解压

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

代码语言:javascript复制
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)
}

0 人点赞