5

我只是在尝试使用 archive/tar 和 compress/gzip,以便自动处理我拥有的一些备份。

我的问题是:我有各种 .tar 文件和 .tar.gz 文件浮动,因此我想提取 .tar.gz 文件的哈希 (md5) 和 .tar 文件的哈希 (md5)同样,理想情况下是一次运行。

到目前为止,我的示例代码对于 .tar.gz 中文件的哈希以及 .gz 都可以正常工作,但是 .tar 的哈希是错误的,我无法找出问题所在.

我查看了 tar/reader.go 文件,发现其中有一些跳过,但我认为一切都应该在 io.Reader 接口上运行,因此 TeeReader 仍然应该捕获所有字节。

package main

import (
    "archive/tar"
    "compress/gzip"
    "crypto/md5"
    "fmt"
    "io"
    "os"
)

func main() {
    tgz, _ := os.Open("tb.tar.gz")
    gzMd5 := md5.New()
    gz, _ := gzip.NewReader(io.TeeReader(tgz, gzMd5))
    tarMd5 := md5.New()
    tr := tar.NewReader(io.TeeReader(gz, tarMd5))
    for {
        fileMd5 := md5.New()
        hdr, err := tr.Next()
        if err == io.EOF {
            break
        }
        io.Copy(fileMd5, tr)
        fmt.Printf("%x  %s\n", fileMd5.Sum(nil), hdr.Name)
    }
    fmt.Printf("%x  tb.tar\n", tarMd5.Sum(nil))
    fmt.Printf("%x  tb.tar.gz\n", gzMd5.Sum(nil))
}

现在看下面的例子:

$ echo "a" > a.txt
$ echo "b" > b.txt
$ tar cf tb.tar a.txt b.txt 
$ gzip -c tb.tar > tb.tar.gz
$ md5sum a.txt b.txt tb.tar tb.tar.gz

60b725f10c9c85c70d97880dfe8191b3  a.txt
3b5d5c3712955042212316173ccf37be  b.txt
501352dcd8fbd0b8e3e887f7dafd9392  tb.tar
90d6ba204493d8e54d3b3b155bb7f370  tb.tar.gz

在带有来自 Ubuntu 存储库的 go 1.02 的 Linux Mint 14(基于 Ubuntu 12.04)上,我的 go 程序的结果是:

$ go run tarmd5.go 
60b725f10c9c85c70d97880dfe8191b3  a.txt
3b5d5c3712955042212316173ccf37be  b.txt
a26ddab1c324780ccb5199ef4dc38691  tb.tar
90d6ba204493d8e54d3b3b155bb7f370  tb.tar.gz

因此,除了 tb.tar 之外的所有哈希都符合预期。(当然,如果您重试该示例,您的 .tar 和 .tar.gz 将与此不同,因为时间戳不同)

任何有关如何使其工作的提示将不胜感激,但我真的更希望它在 1 次运行中运行(使用 TeeReaders)。

4

1 回答 1

5

出现此问题是因为 tar 不会从您的阅读器读取每个字节。在对每个文件进行散列后,您需要清空阅读器以确保读取和散列每个字节。我通常这样做的方式是io.Copy()阅读直到EOF。

package main

import (
    "archive/tar"
    "compress/gzip"
    "crypto/md5"
    "fmt"
    "io"
    "io/ioutil"
    "os"
)

func main() {
    tgz, _ := os.Open("tb.tar.gz")
    gzMd5 := md5.New()
    gz, _ := gzip.NewReader(io.TeeReader(tgz, gzMd5))
    tarMd5 := md5.New()
    tee := io.TeeReader(gz, tarMd5) // need the reader later
    tr := tar.NewReader(tee)
    for {
        fileMd5 := md5.New()
        hdr, err := tr.Next()
        if err == io.EOF {
            break
        }
        io.Copy(fileMd5, tr)
        fmt.Printf("%x  %s\n", fileMd5.Sum(nil), hdr.Name)
    }
    io.Copy(ioutil.Discard, tee) // read unused portions of the tar file
    fmt.Printf("%x  tb.tar\n", tarMd5.Sum(nil))
    fmt.Printf("%x  tb.tar.gz\n", gzMd5.Sum(nil))
}

另一种选择是io.Copy(tarMd5, gz)在 tarMd5.Sum() 调用之前添加。我认为第一种方法更清晰,即使我需要添加/修改四行而不是一行。

于 2013-03-02T22:51:32.553 回答