如何检查两个大文件在Amazon S3上是否相同?
我需要在亚马逊S3上用boto移动大文件(超过5GB),在同一个存储桶里来回移动。为此,我需要使用分片上传的API,这个API不使用md5校验和来生成etag。
虽然我觉得(其实只有98%确定)我的代码是对的,但我想在删除原文件之前确认新复制的文件没有损坏。不过,我找不到其他方法,除了下载这两个文件然后在本地比较,这对于5GB以上的文件来说,过程会非常漫长。
顺便说一下,下面是我用boto复制大文件的代码,也许能帮助到其他人。如果我的问题没有好的解决方案,或许有人能发现bug,帮我避免数据损坏。
import boto
copy_size = 1000000000 #1e9
bucket_name = 'mybucket'
orig_key_name = 'ABigFile'
dest_key_name = 'ABigFile.clone'
s3 = boto.connect_s3()
mybucket = s3.get_bucket(bucket_name)
key = mybucket.get_key(orig_key_name)
mp = mybucket.initiate_multipart_upload(dest_key_name) #keyname
print 'key size: ', key.size
count = 1
start = 0
end = -1
while end < key.size-1:
print 'count: ', count
start = end + 1
end = min( key.size -1 , start + copy_size )
mp.copy_part_from_key(bucket_name, orig_key_name, count , start, end )
count+=1
mp.complete_upload()
这段代码只适用于原始文件大小大于等于5368709121字节的情况。
2 个回答
要实现你想要的功能,首先得了解AWS是怎么计算多部分上传的etag的。如果你手上有这个对象的本地副本,你可以计算每个部分的md5值,然后和每次调用mp.copy_part_from_key()返回的etag进行比较。不过听起来你没有本地副本。
另外,在boto库中还有一个不太明显的小问题,这个问题在非常少见的情况下可能会导致你丢失数据。如果你查看boto的源代码,会发现mp.complete_upload()这个函数其实并没有使用AWS上传时返回的任何部分的etag。当你使用multipart_complete时,它实际上会重新生成一个新的多部分列表,并从S3获取新的部分和etag。这是有风险的,因为AWS的数据一致性是最终一致的,这意味着这个列表可能不完整。理想情况下,multipart_complete()应该使用每次远程复制返回的etag和部分信息,这样才会更安全。这也是亚马逊在文档中推荐的做法(可以查看多部分上传列表下的说明)。
不过,如果你确认两个对象的文件大小是一样的,那么问题发生的可能性就小很多。我认为最糟糕的情况是某个部分没有出现在多部分上传的列表中。只要列出的部分本身是正确的,就不会有问题。
你应该能够在数据流上计算SHA-1哈希值(可以查看这个StackOverflow的讨论,里面有C++的代码,可能会给你一些Python方法的启发)。通过将你计算出的哈希数据流重定向到相当于/dev/null
的地方,你就可以在不先下载文件到本地的情况下,比较两个文件的SHA-1哈希值。