2012-11-28 1 views
7

Go에 tar_gz 도구를 쓰고 싶습니다. 입력은 리눅스 명령과 같다 :golang의 tar.gz 파일에 [파일뿐 아니라] 디렉토리를 작성하는 방법

$tar czvf targetFileName inputDirectoryPath 

가정하자 나는 inputDirectory는 다음과 같이 구성했다 : 명령을 사용합니다 : 예를 들어

test [dir] 
-- 0.txt 
    -- 1 [sub dir] 
     -- 1.txt 

$tar czvf test.tar.gz test/ 

우리는 타르와를 gzip을 수 있습니다 전체 테스트 디렉토리.


내 문제는 테스트 디렉토리에있는 모든 파일을 반복적으로 반복하고 test.tar.gz 파일에 파일을 작성하기 위해 tar 및 gz 경로를 작성할 수 있다는 점입니다. 그러나 나는 test.tar.gz에 디렉토리를 쓰는 방법을 모른다. 내 프로그램을 실행 한 후, test.tar.gz 파일의 구조는 다음과 같습니다

0.txt 
1.txt 

사람이 어떻게 출력 tar.gz 파일에 반복적으로 디렉토리를 작성하는 방법을 말해 줄래. 고마워.

package main 

    import (
     "fmt" 
     "os" 
     "io" 
     "log" 
     "strings" 
     "archive/tar" 
     "compress/gzip" 
    ) 

    func handleError(_e error) { 
     if _e != nil { 
     log.Fatal(_e) 
     } 
    } 

    func TarGzWrite(_path string, tw *tar.Writer, fi os.FileInfo) { 
     fr, err := os.Open(_path) 
     handleError(err) 
     defer fr.Close() 

     h := new(tar.Header) 
     h.Name = fi.Name() 
     h.Size = fi.Size() 
     h.Mode = int64(fi.Mode()) 
     h.ModTime = fi.ModTime() 

     err = tw.WriteHeader(h) 
     handleError(err) 

     _, err = io.Copy(tw, fr) 
     handleError(err) 
    } 

    func IterDirectory(dirPath string, tw *tar.Writer) { 
     dir, err := os.Open(dirPath) 
     handleError(err) 
     defer dir.Close() 
     fis, err := dir.Readdir(0) 
     handleError(err) 
     for _, fi := range fis { 
     curPath := dirPath + "/" + fi.Name() 
     if fi.IsDir() { 
      //TarGzWrite(curPath, tw, fi) 
      IterDirectory(curPath, tw) 
     } else { 
      fmt.Printf("adding... %s\n", curPath) 
      TarGzWrite(curPath, tw, fi) 
     } 
     } 
    } 

    func TarGz(outFilePath string, inPath string) { 
     // file write 
     fw, err := os.Create(outFilePath) 
     handleError(err) 
     defer fw.Close() 

     // gzip write 
     gw := gzip.NewWriter(fw) 
     defer gw.Close() 

     // tar write 
     tw := tar.NewWriter(gw) 
     defer tw.Close() 

     IterDirectory(inPath, tw) 

     fmt.Println("tar.gz ok") 
    } 

    func main() { 
     targetFilePath := "test.tar.gz" 
     inputDirPath := "test/" 
     TarGz(targetFilePath, strings.TrimRight(inputDirPath, "/")) 
     fmt.Println("Hello, World") 
    } 

답변

10

전체 경로가 아닌 타르에 파일 이름 만 추가하는 것입니다. Tar가 디렉토리를 이해할 수 있도록 전체 경로를 유지해야합니다.

h.Name = fi.Name() 

은해야합니다 : 리눅스에

h.Name = _path 

, tar -tvf test.tar.gz의 출력 :

-rw-rw-r-- 0/0    0 2012-11-28 11:17 test/0.txt 
-rw-rw-r-- 0/0    0 2012-11-28 11:17 test/sub/1.txt 
+0

보다 큼 많이 ks. 그것은 작동합니다. – MadCrazy

4

대안이 (가) 파일 경로에 내장 된 사용하는 것입니다 당신은 하나 개의 라인을 변경해야합니다. 도보 기능

// root_directory has been set further up 

walkFn := func(path string, info os.FileInfo, err error) error { 
    if info.Mode().IsDir() { 
     return nil 
    } 
    // Because of scoping we can reference the external root_directory variable 
    new_path := path[len(root_directory):] 
    if len(new_path) == 0 { 
     return nil 
    } 
    fr, err := os.Open(path) 
    if err != nil { 
     return err 
    } 
    defer fr.Close() 

    if h, err := tar.FileInfoHeader(info, new_path); err != nil { 
     log.Fatalln(err) 
    } else { 
     h.Name = new_path 
     if err = tw.WriteHeader(h); err != nil { 
      log.Fatalln(err) 
     } 
    } 
    if length, err := io.Copy(tw, fr); err != nil { 
     log.Fatalln(err) 
    } else { 
     fmt.Println(length) 
    } 
    return nil 
} 

if err = filepath.Walk(root_directory, walkFn); err != nil { 
    return err 
} 
+1

'new_path : = path [len (root_directory) +1 :]'이 각 파일의 접두어를 피하는 것이 더 낫다고 생각합니다. – DarKnight

관련 문제