package filetag import ( "bytes" "crypto/sha1" "encoding/base64" "io" "mime/multipart" "os" ) const ( _BlockBits = 22 // Indicate that the blockSize is 4M _BlockSize = 1 << _BlockBits ) func blockCount(fileSize int64) int { return int((fileSize + (_BlockSize -1)) >> _BlockBits) } // 计算文件SHA1值 func sha1Value(b []byte, r io.Reader) ([]byte, error) { h := sha1.New() _, err := io.Copy(h, r) if err != nil { return nil, err } return h.Sum(b), nil } // 依据文件大小将计算出etag值 func Filename(fn string) (etag string, err error) { f, err := os.Open(fn) if err != nil { return } defer f.Close() fi, err := f.Stat() if err != nil { return } fileSize := fi.Size() blockCnt := blockCount(fileSize) sha1Buf := make([]byte, 0, 21) if blockCnt <= 1 { // file size <= 4M sha1Buf = append(sha1Buf, 0x16) sha1Buf, err = sha1Value(sha1Buf, f) if err != nil { return } } else { // file size > 4M sha1Buf = append(sha1Buf, 0x96) sha1BlockBuf := make([]byte, 0, blockCnt * 20) for i := 0; i < blockCnt; i ++ { body := io.LimitReader(f, _BlockSize) sha1BlockBuf, err = sha1Value(sha1BlockBuf, body) if err != nil { return } } sha1Buf, _ = sha1Value(sha1Buf, bytes.NewReader(sha1BlockBuf)) } etag = base64.URLEncoding.EncodeToString(sha1Buf) return } // 依据文件大小将计算出etag值 func Multipart(f *multipart.FileHeader) (etag string, err error) { src, err := f.Open() if err != nil { return } defer src.Close() blockCnt := blockCount(f.Size) sha1Buf := make([]byte, 0, 21) if blockCnt <= 1 { // file size <= 4M sha1Buf = append(sha1Buf, 0x16) sha1Buf, err = sha1Value(sha1Buf, src) if err != nil { return } } else { // file size > 4M sha1Buf = append(sha1Buf, 0x96) sha1BlockBuf := make([]byte, 0, blockCnt * 20) for i := 0; i < blockCnt; i ++ { body := io.LimitReader(src, _BlockSize) sha1BlockBuf, err = sha1Value(sha1BlockBuf, body) if err != nil { return } } sha1Buf, _ = sha1Value(sha1Buf, bytes.NewReader(sha1BlockBuf)) } etag = base64.URLEncoding.EncodeToString(sha1Buf) return }