2016-07-19 11 views
2

그래서 여러 디렉토리와 파일에서 tar.gz 파일 파일을 채취하려고합니다.파일과 디렉토리에서 tar.gz 파일을 만들 때`쓰기가 너무 오래 걸림`오류가 발생했습니다.

tar -cvzf sometarfile.tar.gz somedir/ someotherdir/ somefile.json somefile.xml 

디렉토리 안에 다른 디렉토리가 있다고 가정합니다.

paths := []string{ 
     "somedir/", 
     "someotherdir/", 
     "somefile.json", 
     "somefile.xml", 
    } 

이러한 사용 : 내가 입력으로 이것을 가지고

func TarFilesDirs(paths []string, tarFilePath string) error { 
     // set up the output file 
     file, err := os.Create(tarFilePath) 
     if err != nil { 
      return err 
     } 

     defer file.Close() 
     // set up the gzip writer 
     gz := gzip.NewWriter(file) 
     defer gz.Close() 

     tw := tar.NewWriter(gz) 
     defer tw.Close() 

     // add each file/dir as needed into the current tar archive 
     for _,i := range paths { 
      if err := tarit(i, tw); err != nil { 
       return err 
      } 
     } 

     return nil 
    } 

func tarit(source string, tw *tar.Writer) error { 
    info, err := os.Stat(source) 
    if err != nil { 
     return nil 
    } 

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

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

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

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

      if err := tw.WriteHeader(header); 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(tw, file) 
      if err != nil { 
       log.Println("failing here") 
       return err 
      } 

      return err 
     }) 
} 

문제 :

archive/tar: write too long 

오류를 때 디렉토리 내가지고있어 큰 경우 나는 모든 것을 제거한다.

은 ...

어떤 아이디어를 아이디어 뛰쳐 해결책을 찾기 위해 노력하고 이것에 많은 시간을 낭비?

감사

답변

5

나는 tar.FileInfoHeader의 문서에서 더 자세히보고 할 때까지 나는 비슷한 문제가 발생했다가 :

FileInfoHeader가 생성하는 부분적으로 채워진 헤더 from fi. fi가 심볼릭 링크를 설명하면 FileInfoHeader는 링크 대상으로 링크를 기록합니다. fi가 디렉토리를 설명하면 이름에 슬래시가 추가됩니다. os.FileInfo의 Name 메서드는 설명하는 파일의 기본 이름 만 반환하기 때문에 반환 된 머리글의 Name 필드를 수정하여 파일의 전체 경로 이름을 제공해야 할 수 있습니다.

기본적으로 FileInfoHeader는 당신이 WriteHeader 그것을 기록하기 전에 모든 헤더 필드를 작성 보장 할 수 없습니다, 당신은 구현 보면 크기 필드는 regular 파일에 설정되어 있습니다. 코드 스 니펫은 디렉토리 만 처리하는 것처럼 보입니다. 즉, 다른 일반 파일이 아닌 경우 0의 크기로 헤더를 작성한 다음 디스크에있는 0이 아닌 크기의 특수 파일을 타르에 복사하려고 시도합니다. Go는 ErrWriteTooLong을 반환하여 깨진 타르를 만들지 못하도록합니다.

나는이 문제를 생각해 냈다.

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

     var link string 
     if info.Mode()&os.ModeSymlink == os.ModeSymlink { 
      if link, err = os.Readlink(path); err != nil { 
       return check(err) 
      } 
     } 

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

     header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, directory)) 
     if err = tw.WriteHeader(header); err != nil { 
      return check(err) 
     } 

     if !info.Mode().IsRegular() { //nothing more to do for non-regular 
      return nil 
     } 

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

     if _, err = io.CopyBuffer(tw, fh, buf); err != nil { 
      return check(err) 
     } 
     return nil 
}) 
+0

예 대답은 –

+0

입니다. 파일이 디스크에서 변경되어 더 길어질 수도 있습니다. –

0

쓰기는 tar 아카이브의 현재 항목을 기록합니다. WriteHeader 뒤에 hdr.Size 바이트 이상 쓰면 Write가 ErrWriteTooLong 오류를 반환합니다.

헤더에 추가 할 수있는 Size 옵션이 있습니다. ...

참조 그것을 시도하지만 어쩌면이 도움이되지 않은 또한 https://golang.org/pkg/archive/tar/