2012-11-28 25 views
7

Go'da bir tar_gz aracı yazmak istiyorum. giriş sadece linux komutu gibidir:bir dizinin nasıl yazılacağı [sadece içindeki dosyalar] golang'daki bir tar.gz dosyasına

$tar czvf targetFileName inputDirectoryPath 

varsayalım Bir inputDirectory olarak aşağıda yapılandırdık: komutunu kullanın: Örnek için

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

$tar czvf test.tar.gz test/ 

biz katran ve gzip edebilirsiniz tüm test dizini.


Sorunum, test dizinindeki tüm dosyaları yinelemeli olarak yinelemek ve dosyayı test.tar.gz dosyasına yazmak için bir tar ve gz yolu yazabilirim. Ama test.tar.gz'ye nasıl bir dizin yazacağımı bilmiyorum. Benim program çalıştırdıktan sonra test.tar.gz dosyada yapıdır:

0.txt 
1.txt 

herkes nasıl çıktı tar.gz dosyasına yinelemeli dizini yazmak için bana söyleyebilir. Çok teşekkürler.

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

cevap

10

Sadece dosya adını katmanın tamamına değil, katrana ekliyorsunuz. Tar'in dizinleri anlayabilmesi için yolun tamamını tutmalısın.

h.Name = fi.Name() 

olmalı: Linux'ta

h.Name = _path 

, tar -tvf test.tar.gz çıktısını:

-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

Çok ks. İşe yarıyor. – MadCrazy

4

alternatif filepath inşa kullanmaktır sadece bir satır değiştirmeniz gerekir. Yürüme işlevi

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

Sanırım 'new_path: = yol [len (root_directory) +1:]' her dosyanın önekinden/önlemek için daha iyidir. – DarKnight