我已经使用Amazon S3进行一段时间的备份了.通常,在我上传文件后,我会检查MD5总和匹配,以确保我做了一个很好的备份.S3有"etag"标题用于给出这个总和.
但是,当我最近上传一个大文件时,Etag似乎不再是md5总和.它有额外的数字和连字符"696df35ad1161afbeb6ea667e5dd5dab-2861".我找不到任何关于这种变化的文件.我已经使用S3管理控制台和Cyberduck进行了检查.
我找不到有关此更改的任何文档.有什么指针吗?
小智 36
如果使用multipart上传任何文件,那么您将始终获得此类ETag.但是,如果您将整个文件作为单个文件上传,那么您将获得以前的ETag.
Bucket Explorer为您提供正常的ETag,直到5Gb上传为多部分操作.但更多的是它没有提供.
https://forums.aws.amazon.com/thread.jspa?messageID=203510#203510
小智 29
当您使用multipart上传文件时,Amazon S3使用不同的算法(通常不是MD5 Sum)计算Etag.
此算法详述如下:http://permalink.gmane.org/gmane.comp.file-systems.s3.s3tools/583
"计算文件每个上传部分的MD5哈希值,将哈希值连接成一个二进制字符串,并计算该结果的MD5哈希值."
我只是用bash开发一个工具来计算它,s3md5:https://github.com/Teachnova/s3md5
例如,要计算使用多部分上传的文件foo.bin的 Etag,块大小为15 MB,则
# s3md5 15 foo.bin
Run Code Online (Sandbox Code Playgroud)
现在您可以检查一个非常大的文件(大于5GB)的完整性,因为您可以计算本地文件的Etag并将其与S3 Etag进行比较.
Spe*_*dge 21
也在python ...
# Max size in bytes before uploading in parts.
AWS_UPLOAD_MAX_SIZE = 20 * 1024 * 1024
# Size of parts when uploading in parts
AWS_UPLOAD_PART_SIZE = 6 * 1024 * 1024
#
# Function : md5sum
# Purpose : Get the md5 hash of a file stored in S3
# Returns : Returns the md5 hash that will match the ETag in S3
def md5sum(sourcePath):
filesize = os.path.getsize(sourcePath)
hash = hashlib.md5()
if filesize > AWS_UPLOAD_MAX_SIZE:
block_count = 0
md5string = ""
with open(sourcePath, "rb") as f:
for block in iter(lambda: f.read(AWS_UPLOAD_PART_SIZE), ""):
hash = hashlib.md5()
hash.update(block)
md5string = md5string + binascii.unhexlify(hash.hexdigest())
block_count += 1
hash = hashlib.md5()
hash.update(md5string)
return hash.hexdigest() + "-" + str(block_count)
else:
with open(sourcePath, "rb") as f:
for block in iter(lambda: f.read(AWS_UPLOAD_PART_SIZE), ""):
hash.update(block)
return hash.hexdigest()
Run Code Online (Sandbox Code Playgroud)
这是一个powershell函数来计算文件的Amazon ETag:
$blocksize = (1024*1024*5)
$startblocks = (1024*1024*16)
function AmazonEtagHashForFile($filename) {
$lines = 0
[byte[]] $binHash = @()
$md5 = [Security.Cryptography.HashAlgorithm]::Create("MD5")
$reader = [System.IO.File]::Open($filename,"OPEN","READ")
if ((Get-Item $filename).length -gt $startblocks) {
$buf = new-object byte[] $blocksize
while (($read_len = $reader.Read($buf,0,$buf.length)) -ne 0){
$lines += 1
$binHash += $md5.ComputeHash($buf,0,$read_len)
}
$binHash=$md5.ComputeHash( $binHash )
}
else {
$lines = 1
$binHash += $md5.ComputeHash($reader)
}
$reader.Close()
$hash = [System.BitConverter]::ToString( $binHash )
$hash = $hash.Replace("-","").ToLower()
if ($lines -gt 1) {
$hash = $hash + "-$lines"
}
return $hash
}
Run Code Online (Sandbox Code Playgroud)
这是Go中的一个例子:
func GetEtag(path string, partSizeMb int) string {
partSize := partSizeMb * 1024 * 1024
content, _ := ioutil.ReadFile(path)
size := len(content)
contentToHash := content
parts := 0
if size > partSize {
pos := 0
contentToHash = make([]byte, 0)
for size > pos {
endpos := pos + partSize
if endpos >= size {
endpos = size
}
hash := md5.Sum(content[pos:endpos])
contentToHash = append(contentToHash, hash[:]...)
pos += partSize
parts += 1
}
}
hash := md5.Sum(contentToHash)
etag := fmt.Sprintf("%x", hash)
if parts > 0 {
etag += fmt.Sprintf("-%d", parts)
}
return etag
}
Run Code Online (Sandbox Code Playgroud)
这只是一个例子,你应该处理错误和东西
如果您使用分段上传,“etag”不是数据的 MD5 和(请参阅计算大于 5GB 的文件的 Amazon-S3 Etag 的算法是什么?)。人们可以通过包含破折号“-”的 etag 来识别这种情况。
现在,有趣的问题是如何在不下载的情况下获得数据的实际 MD5 和?一种简单的方法是将对象“复制”到其自身上,这不需要下载:
s3cmd cp s3://bucket/key s3://bucket/key
这将导致 S3 重新计算 MD5 和并将其存储为刚刚复制的对象的“etag”。“复制”命令直接在S3上运行,即没有对象数据传输到S3或从S3传输,因此这需要很少的带宽!(注意:不要使用 s3cmd mv;这会删除您的数据。)
底层 REST 命令是:
PUT /key HTTP/1.1
Host: bucket.s3.amazonaws.com
x-amz-copy-source: /buckey/key
x-amz-metadata-directive: COPY
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
47579 次 |
| 最近记录: |