Golang:使用minio分片上传s3,以及计算Etag校验和

3,452 阅读2分钟

minio分片上传使用接口:

先贴上传主要使用的接口:

// 初始化接口
minioCore := minio.NewCore()
// 申请uploadId
minioCore.NewMultipartUpload()
// 上传单个分片
minioCore.PutObjectPart()
// 已上传列表
minioCore.ListObjectParts()
// 合并分片
minioCore.CompleteMultipartUpload()

s3 Etag 计算原理:

Etag签名原理:

//单个不分片
2665774b2f902a9957290f38d1853881
//分片:前面部分d41d8c...的(即-号前)是ETag;后面部分2表示文件是分了两个Part上传。
d41d8cd98f00b204e9800998ecf8427e-2

在S3存储桶中,常用ETag来标记文件或者比较文件是否相同。存在两种情况:

  1. 在单个文件为一个整体上传时,且单个文件不大于5G时,Etag等于MD5;
  2. 在单文件分片上传时,不管文件多大,Etag为单个分片校验和—Num。 image.png 也就是要连接分片md5、解码十六进制,并获得批次的MD5校验和。
文件直接获取Etag:
Golang
package main

import (
   "crypto/md5"
   "fmt"
   "io"
   "os"
)

func calcEtag(inputfile string, partsize int64) string {
   var md5Digests []byte
   f, err := os.Open(inputfile)
   if err != nil {
      panic(err)
   }
   defer f.Close()

   num := 0
   buf := make([]byte, partsize)
   for {
      n, err := f.Read(buf)
      if err != nil && err != io.EOF {
         panic(err)
      }
      if n == 0 {
         break
      }
      a := md5.Sum(buf[:n])
      md5Digests = append(md5Digests, a[:]...)
      num++
   }
   return fmt.Sprintf("%x-%d", md5.Sum(md5Digests), num)
}

func main() {
   // 块的大小5242880(5 * 1024 * 1024),是上传的分块大小。
   fmt.Println(calcEtag("text.word", 5242880))
}
Python
#!/usr/bin/env python
#*- coding: utf_8 *
import hashlib
from hashlib import md5
def calc_etag(inputfile,partsize=5242880):
        md5_digests = []
        with open(inputfile,'rb') as f:
                for chunk in iter(lambda: f.read(partsize),b''):
                        md5_digests.append(md5(chunk).digest())
        return md5(b''.join(md5_digests)).hexdigest()+'-'+str(len(md5_digests))
if __name__ == "__main__":
        print(calc_etag("text.word"))
通过分片Md5计算Etag:
minioClient, _ := minio.NewCore("endpoint", &minio.Options{
   Creds:  credentials.NewStaticV4("accessKey", "secretKey", ""),
   Secure: false,
})
partsInfo, err := listObjectParts(context.Background(), minioClient, uploadBucket, uploadName, uploadId)
if err != nil {
   return
}

var md5Str string
for _, part := range partsInfo {
   md5Str += part.ETag
}

// 将HEX编码的字符串转换为HEX数据,即md5字符串解码十六进制
data1, _ := hex.DecodeString(md5Str)
sprintf := fmt.Sprintf("%x-%d", md5.Sum(data1), len(partsInfo))
fmt.Println(sprintf)

先这样吧,把整理的精华部分贴出来,后面再完善,有问题可以讨论。

查阅资料:

qastack:qastack.cn/programming…
知乎:zhuanlan.zhihu.com/p/109773532
他人博客:evvail.com/2020/07/24/…