我只是尝试使用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))
}
Run Code Online (Sandbox Code Playgroud)
现在为以下示例:
$ 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
Run Code Online (Sandbox Code Playgroud)
在Linux Mint 14(基于Ubuntu 12.04)上,从Ubuntu存储库获取1.02,我的go程序的结果是:
$ go run tarmd5.go
60b725f10c9c85c70d97880dfe8191b3 a.txt
3b5d5c3712955042212316173ccf37be b.txt
a26ddab1c324780ccb5199ef4dc38691 tb.tar
90d6ba204493d8e54d3b3b155bb7f370 tb.tar.gz
Run Code Online (Sandbox Code Playgroud)
所以除了tb.tar之外的所有哈希值都是预期的.(当然,如果你重试那个例子,你的.tar和.tar.gz将与此不同,因为时间戳不同)
任何有关如何使其工作的提示都将非常感激,我真的更希望在1次运行中使用它(使用TeeReaders).
出现此问题是因为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))
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是io.Copy(tarMd5, gz)在tarMd5.Sum()调用之前添加.我认为第一种方式更清晰,即使我需要添加/修改四行而不是一行.