2012-11-28 8 views
7

Ich möchte ein Tar_gz Werkzeug in Go schreiben. Der Eingang ist wie Linux-Befehl:Wie schreibe ich ein Verzeichnis [nicht nur die Dateien darin] in eine tar.gz-Datei in Golang

$tar czvf targetFileName inputDirectoryPath 

Angenommen, ich habe ein eingabeverzeichnis wie folgt aufgebaut:

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

Beispiel: verwenden Sie den Befehl:

$tar czvf test.tar.gz test/ 

wir können die tar und gzip ganzes Testverzeichnis


Mein Problem ist, ich kann eine tar-und GZ-Route schreiben, um rekursiv alle Dateien im Test-Verzeichnis zu iterieren und die Datei in die Datei test.tar.gz schreiben. Aber ich weiß nicht, wie man ein Verzeichnis in test.tar.gz schreibt. Nach meinem Programm ausgeführt wird, ist die Struktur in test.tar.gz Datei:

0.txt 
1.txt 

Kann mir jemand sagen, wie das Verzeichnis rekursiv mit dem Ausgang tar.gz-Datei zu schreiben. Danke vielmals.

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") 
    } 

Antwort

10

Sie fügen dem Teer nur den Dateinamen hinzu, nicht den gesamten Pfad. Sie müssen den gesamten Pfad für Tar beibehalten, um Verzeichnisse verstehen zu können. Sie müssen nur eine Zeile ändern:

h.Name = fi.Name() 

Sollte sein:

h.Name = _path 

Unter Linux die Ausgabe von 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

Als ks viel. Es klappt. – MadCrazy

4

Eine Alternative ist die in Filepath gebaut zu verwenden. Walk-Funktion

// 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

Ich denke 'new_path: = Pfad [len (root_directory) +1:]' ist besser zu vermeiden/von Präfix jeder Datei. – DarKnight

Verwandte Themen