golang訪問tar檔案
下面例子提取一個tar檔案的內容:
package mainimport ( "io" "os" "fmt" "path" "encoding/json" "archive/tar")func extract(tarfile string) { reader, err := os.Open(tarfile) if err != nil { fmt.Printf("ERROR: cannot read tar file, error=[%v]\n", err) return } defer reader.Close() tarReader := tar.NewReader(reader) for { header, err := tarReader.Next() if err == io.EOF { break } else if err != nil { fmt.Printf("ERROR: cannot read tar file, error=[%v]\n", err) return } j, err := json.Marshal(header) if err != nil { fmt.Printf("ERROR: cannot parse header, error=[%v]\n", err) return } fmt.Printf("header=%s\n", string(j)) info := header.FileInfo() if info.IsDir() { if err = os.MkdirAll(header.Name, 0755); err != nil { fmt.Printf("ERROR: cannot mkdir file, error=[%v]\n", err) return } } else { if err = os.MkdirAll(path.Dir(header.Name), 0755); err != nil { fmt.Printf("ERROR: cannot file mkdir file, error=[%v]\n", err) return } file, err:= os.OpenFile(header.Name, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) if err != nil { fmt.Printf("ERROR: cannot open file, error=[%v]\n", err) return } defer file.Close() _, err =io.Copy(file, tarReader) if err != nil { fmt.Printf("ERROR: cannot write file, error=[%v]\n", err) return } } }}
tar檔案的格式定義:
https://www.gnu.org/software/tar/manual/html_node/Standard.html
每一個檔案包含一個512位元組的頭部資訊,然後是檔案內容;所以對於小檔案產生的tar檔案反而比原檔案大很多。每一個原檔案打到tar裡面至少包含1024位元組(512的頭資訊,然後是檔案內容,不足512位元組的後面補零);所以如果原檔案大小為一個位元組大小,產生的tar檔案就會有1024位元組大小,結論就是小檔案不宜使用tar.gz壓縮儲存。
使用tar很自然的就會想到gz,因為tar.gz。
下面的模板例子用來處理tar.gz的讀寫:
讀取tar.gz檔案內容:
body := bytes.NewReader([]byte{...}) gr, err := gzip.NewReader(body) tr := tar.NewReader(gr) for { header, err := tr.Next() if err != nil { // We only get here if there are no more entries to scan break } HANLD_AN_ENTRY }
產生tar.gz檔案:
payload := bytes.NewBuffer(nil) gw := gzip.NewWriter(payload) tw := tar.NewWriter(gw) for _, file := range files { info, err := os.Stat(file) header, err := tar.FileInfoHeader(info, file) err = tw.WriteHeader(header); fd, err := os.Open(file) _, err := io.Copy(tw, bufio.NewReader(fd)); } tw.Close() gw.Close() write payload.Bytes() into file.