我想在Go中编写一个tar_gz工具。输入就像linux命令:
$tar czvf targetFileName inputDirectoryPath
假设我有一个inputDirectory结构如下:
test [dir]
-- 0.txt
-- 1 [sub dir]
-- 1.txt
例如:使用命令:
$tar czvf test.tar.gz test/
我们可以tar和gzip整个测试目录。
我的问题是我可以写一个tar和gz路由来递归迭代测试目录中的所有文件并将文件写入test.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" )
}
答案 0 :(得分:11)
您只是将文件名添加到tar,而不是整个路径。您需要保持Tar的整个路径才能理解目录。你只需要换一行:
h.Name = fi.Name()
应该是:
h.Name = _path
在Linux上,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
答案 1 :(得分:4)
另一种方法是使用内置的filepath.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
}