我正在通过Go中编写的Api将文件上传到GCP云存储,它运行良好(选项I(。我想知道我是否可以在不将文件存储在内存中的情况下计算校验和。我已经尝试了选项II中的代码,在阅读器中循环并更新校验和,但没有起作用,似乎我必须在进行第一次写入之前预先初始化校验和值CRC32C,正如文档中所说的那样;ObjectAttrs":https://godoc.org/cloud.google.com/go/storage#Writer
我猜我不能同时流式传输和生成CRC32校验和。是这样吗?。Cloud Storage Go客户端在写入程序中默认没有任何校验和机制吗?。
(我跳过了代码示例中的错误(
选项一:
...
func example(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("file")
defer file.Close()
//create empty buffer
buf := bytes.NewBuffer(nil)
//Writer
wc := bucket.Object(filename).NewWriter(ctx)
//calculate checksum
wc.CRC32C = crc32.Checksum(buf.Bytes(), crc32.MakeTable(crc32.Castagnoli))
wc.SendCRC32C = true
//copy buffer to bucket
_, err = io.Copy(wc, buf)
wc.Close()
...
}
选项二:
...
func example(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("file")
defer file.Close()
var err error
table := crc32.MakeTable(crc32.Castagnoli)
wc := bucket.Object(filename).NewWriter(ctx)
checksum := crc32.Checksum([]byte(""), table)
wc.SendCRC32C = true
buf := make([]byte, 32*1024)
for {
nr, er := file.Read(buf)
if nr > 0 {
checksum = crc32.Update(checksum, table, buf[:nr])
nw, ew := wc.Write(buf[:nr])
}
if er != nil {
if er == io.EOF {
wc.CRC32C = checksum
break
}
err = er
break
}
}
wc.Close()
...
}
使用io.Writer
包装器,因为大多数哈希器都通过Write
方法更新其哈希。使用这种方法,不需要中间缓冲区,更重要的是,它将主逻辑从管理哈希状态变化的任务中解放出来。
因此,使用helper方法,您可以为任何CRC32
多项式创建一个自定义哈希器,并将其绑定到任何目标io.Writer
:
import (
"hash"
"hash/crc32"
"io"
)
func NewCRCwriter(poly uint32, w io.Writer) *CRCwriter {
return &CRCwriter{
h: crc32.New(crc32.MakeTable(poly)),
w: w,
}
}
type CRCwriter struct {
h hash.Hash32
w io.Writer
}
func (c *CRCwriter) Write(p []byte) (n int, err error) {
n, err = c.w.Write(p) // with each write ...
c.h.Write(p) // ... update the hash
return
}
func (c *CRCwriter) Sum() uint32 { return c.h.Sum32() } // final hash
在您的用例中利用这一点:
file, header, err := r.FormFile("file") // io.Reader
defer file.Close()
wc := bucket.Object(filename).NewWriter(ctx) // io.Writer
crcw := NewCRCwriter(crc32.Castagnoli, wc) // wrapped io.Writer
_, err = io.Copy(crcw, file) // content will be copied and hashed
if err != nil { /* */ }
wc.CRC32C = crcw.Sum() // final CRC32 hash
wc.SendCRC32C = true
wc.Close()