2012-11-28 21 views
7

Voglio scrivere uno strumento tar_gz in Go. L'ingresso è proprio come comando di Linux:come scrivere una directory [non solo i file in esso] in un file tar.gz in golang

$tar czvf targetFileName inputDirectoryPath 

Supponiamo che io sono un inputDirectory strutturato come di seguito:

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

Per esempio: il comando utilizzare:

$tar czvf test.tar.gz test/ 

possiamo tar e gzip il intera directory di test.


il mio problema è che posso scrivere un catrame e gz percorso per scorrere in modo ricorsivo tutti i file nella directory di prova e scrivere il file test.tar.gz file. Ma non so come scrivere una directory sul test.tar.gz. Dopo aver eseguito il mio programma, la struttura in test.tar.gz file è:

0.txt 
1.txt 

Qualcuno può dirmi come scrivere la directory in modo ricorsivo per il file di output tar.gz. Molte grazie.

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

risposta

10

Si sta solo aggiungendo il nome file a tar, non all'intero percorso. È necessario mantenere l'intero percorso affinché Tar possa essere in grado di comprendere le directory. Hai solo bisogno di cambiare una sola riga:

h.Name = fi.Name() 

dovrebbe essere:

h.Name = _path 

Su Linux, l'uscita del 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

Than ks molto. Funziona. – MadCrazy

4

Un'alternativa è quella di utilizzare il costruito nel filepath. Funzione Walk

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

Penso che 'new_path: = path [len (root_directory) +1:]' è meglio evitare/dal prefisso di ogni file. – DarKnight

Problemi correlati