2013-08-19 4 views
4

이동 파일의 기존 tar 아카이브에 파일을 추가하려면 어떻게해야합니까? 나는 그것을하는 방법에 관해서는 docs에서 명백한 것을 보지 못했다.Golang : 기존 tar 아카이브에 파일 추가

이미 생성 된 tar 파일이 있는데 이미 닫힌 후에 더 추가하고 싶습니다.

편집

워드 프로세서의 예를 변경하고 난 여전히 예상 된 결과를받지 못했습니다, 대답은 주어진 다음과 같습니다. 처음 세 파일은 tar에 쓰여지지만, 파일을 닫고 다시 열면 새로운 파일이 쓰여지지 않습니다. 코드가 제대로 실행됩니다. 내가 뭘 놓치고 있는지 모르겠다.

다음 코드는 readme.txt, gopher.txt, todo.txt의 세 파일이 들어있는 tar 파일을 제공합니다. 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

그게 내가 생각한거야하지만 난 여전히 정상적인 타르 파일처럼 액세스 할 수 있습니다 – Jeff

+0

@ 제프 내가 제공 한 대답을 좀 봐. 'Seek '를 사용하는 것은 여전히 ​​약간 사기성이지만 유효한 tar 파일을 생성합니다. – Intermernet

답변

7

tar file specification 상태 :

타르 아카이브가 512 바이트 일련의 레코드로 구성되어 있습니다. 각 파일 시스템 개체에는 기본 메타 데이터 (경로 이름, 소유자, 사용 권한 등)와 파일 을 포함하는 0 개 이상의 레코드가 저장되는 헤더 레코드가 필요합니다. 아카이브의 끝은 전체적으로 0 바이트의 으로 구성된 두 개의 레코드로 표시됩니다.

이 두 제로 채워진 기록 happens here을 추가하는 이동의 구현입니다. 대신 (

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) 

그것은 읽기/쓰기 파일을 엽니 다

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) 

으로 :

tar 파일 형식 트레일러 (아무것도 기본적으로 1024 바이트) 해결하기 위해 당신은 선을 대체 할 수 append/write-only) 파일의 끝에서 1024 바이트를 찾고 거기에서 씁니다.

작동합니다, 하지만 끔찍한 해킹입니다.

편집 : tar 파일 스펙을 조금 더 잘 이해 한 후에 더 이상이 해킹이 아니라고 생각하지 않습니다.

전체 코드 : http://play.golang.org/p/0zRScmY4AC

+0

IIRC 타르 아카이브는 다음 블록으로 채워지므로이 찾기가 반드시 필요한 것은 아닙니다. – 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 바이트 슬라이스로 정의 된 var 임) – Intermernet

관련 문제