2012-11-28 12 views
7

Goにtar_gzツールを書きたいと思います。入力は、単にLinuxのコマンドのようなものです。例えばgolangのtar.gzファイルに[ファイルだけでなく]ディレクトリを書き込む方法

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

:コマンドを使用します。

$tar czvf test.tar.gz test/ 

を、私たちは、tarとgzip圧縮することができます

$tar czvf targetFileName inputDirectoryPath 

は、私は以下のようにinputDirectoryを構造化していると仮定しますテストディレクトリ全体。


私の問題は、テストディレクトリ内のすべてのファイルを再帰的に反復して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に追加するだけです。あなたはTarがディレクトリを理解できるようにするための全体の道筋を保つ必要があります。あなただけの1行を変更する必要があります。

h.Name = fi.Name() 

は次のようになります。

Linuxでは、 tar -tvf test.tar.gzの出力に
h.Name = _path 

-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

関連する問題