2013-08-19 73 views
4

如何將文件追加到Go中的現有tar歸檔文件中?在docs中我沒有看到有關如何執行此操作的任何明顯信息。Golang:將文件追加到現有的tar歸檔文件

我有一個tar文件已經被創建,我想在它已經關閉後添加更多。

編輯

改變在文檔中的例子和下面的答案給定的,我仍然沒有得到預期的結果。前三個文件正在寫入tar,但是當我關閉並再次打開文件以寫入文件時,新文件永遠不會被寫入。代碼運行良好。我不知道我錯過了什麼。

下面的代碼給了我一個包含三個文件的tar文件:readme.txt,gopher.txt,todo.txt。 foo.bar永遠不會被寫入。

package main 

import (
    "archive/tar" 
    "log" 
    "os" 
) 

func main() { 
    f, err := os.Create("/home/jeff/Desktop/test.tar") 
    if err != nil { 
     log.Fatalln(err) 
    } 

    tw := tar.NewWriter(f) 

    var files = []struct { 
     Name, Body string 
    }{ 
     {"readme.txt", "This archive contains some text files."}, 
     {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"}, 
     {"todo.txt", "Get animal handling licence."}, 
    } 
    for _, file := range files { 
     hdr := &tar.Header{ 
      Name: file.Name, 
      Size: int64(len(file.Body)), 
     } 
     if err := tw.WriteHeader(hdr); err != nil { 
      log.Fatalln(err) 
     } 
     if _, err := tw.Write([]byte(file.Body)); err != nil { 
      log.Fatalln(err) 
     } 
    } 
    if err := tw.Close(); err != nil { 
     log.Fatalln(err) 
    } 
    f.Close() 

    // Open up the file and append more things to it 

    f, err = os.OpenFile("/home/jeff/Desktop/test.tar", os.O_APPEND|os.O_WRONLY, os.ModePerm) 
    if err != nil { 
     log.Fatalln(err) 
    } 
    tw = tar.NewWriter(f) 

    test := "this is a test" 

    hdr := &tar.Header{ 
     Name: "foo.bar", 
     Size: int64(len(test)), 
    } 

    if err := tw.WriteHeader(hdr); err != nil { 
     log.Fatalln(err) 
    } 

    if _, err := tw.Write([]byte(test)); err != nil { 
     log.Fatalln(err) 
    } 

    if err := tw.Close(); err != nil { 
     log.Fatalln(err) 
    } 
    f.Close() 

} 
+0

註釋掉尾部部分會導致一個無效的tar文件。這可能是一個壞主意。 –

+0

這就是我的想法,但我仍然可以像訪問正常的tar文件一樣訪問它 – Jeff

+0

@Jeff看看我提供的答案。使用'Seek'仍然有點不禮貌,但它確實產生了一個有效的tar文件。 – Intermernet

回答

7

tar file specification狀態:

tar歸檔由一系列512字節的記錄。每個文件系統 對象需要一個標題記錄,其中存儲基本元數據(路徑名, 所有者,權限等)以及零個或多個包含任何文件 數據的記錄。存檔的結尾由兩個記錄表示,其中 完全是零字節。

轉到執行添加這兩種填零記錄happens here的。

要解決的tar文件格式拖車(基本上是1024字節的什麼),你可以更換線路:

f, err = os.OpenFile("/home/jeff/Desktop/test.tar", os.O_APPEND|os.O_WRONLY, os.ModePerm) 
if err != nil { 
    log.Fatalln(err) 
} 
tw = tar.NewWriter(f) 

有了:

f, err = os.OpenFile("/home/jeff/Desktop/test.tar", os.O_RDWR, os.ModePerm) 
if err != nil { 
    log.Fatalln(err) 
} 
if _, err = f.Seek(-2<<9, os.SEEK_END); err != nil { 
    log.Fatalln(err) 
} 
tw = tar.NewWriter(f) 

它打開讀/寫文件(而不是的追加/只寫),然後在文件結束之前尋找1024個字節並從那裏寫入。

It works,但它一個可怕的黑客。

編輯:在瞭解了tar文件規範好一點之後,我不再相信這是一種破解。

全碼:http://play.golang.org/p/0zRScmY4AC

+0

無論如何,IIRC tar檔案被填充到下一個區塊,所以這種尋求並不是必需的。 – fuz

+0

@FUZxxl,你很可能是正確的。使用給定的測試代碼,在寫入文件之前,如果不刪除最後的1024個字節,它就不起作用。正如我所說的,這只是反轉tar.Close()函數的最終動作。請參閱http://golang.org/src/pkg/archive/tar/writer.go?s=8343:8486#L305。 – Intermernet

+0

如果您查看源文件[writer.go](http://golang.org/src/pkg/archive/tar/writer.go),請觀察tw.pad。每個文件都被填充到下一個完整塊。 – fuz

2

它只是一個寫入器接口,所以在寫入文件頭後寫入字節。

import (
    "archive/tar" 
    "os" 
) 

f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, os.ModePerm) 
if err != nil { 
// handle error here 
} 

hdr := tar.Header{} 
// populate your header 
tw := tar.NewWriter(f) 
// append a file 
tw.WriteHeader(hdr) 
tw.Write(content_of_file_as_bytes) 

http://golang.org/pkg/archive/tar/#Writer告訴你所有你需要知道的。

編輯:事實證明,tar文件得到一個拖尾,當它關閉時寫入結尾。所以,即使您正在向tar檔案寫入新數據,也不會通過該預告片讀取。所以相反,它看起來像你必須先在tar檔案中讀取,然後將整個檔案重寫到磁盤,這是不理想的。該包不支持必要的東西來追加到他們,但這是我現在可以推薦的最好的。

+0

這是一個好主意,我們可以查看它的實現:https://code.google.com/p/go/codesearch#go/src/pkg/archive/tar/writer.go&q=tar&sq=package:go&l=5&dr = C – nXqd

+0

感謝您的時間。這就是我期待的,但我無法實現它的工作。我編輯了我的問題以顯示我正在使用的代碼示例。 – Jeff

+0

它看起來像預告片可能是一個1KB的空字節片,所以不應該太難處理。請參閱http://golang.org/src/pkg/archive/tar/writer.go?s=8343:8486#L305(「zeroBlock」是當前定義爲512B字節片段的變量) – Intermernet