如果我在亚马逊的 S3 上有现有文件,最简单的方法是获取它们的 md5sum 而不必下载这些文件?
如果我在亚马逊的 S3 上有现有文件,最简单的方法是获取它们的 md5sum 而不必下载这些文件?
据Gael Fraiteur的评论所述,分段上传的ETag似乎不是MD5。在这种情况下,它包含一个减号和一个数字的后缀。然而,即使在减号之前的部分似乎也不是MD5,尽管它与MD5的长度相同。可能后缀是上传的部分数量?
aws s3 cp ...
。 - Mark#!/bin/bash
set -euo pipefail
if [ $# -ne 2 ]; then
echo "Usage: $0 file partSizeInMb";
exit 0;
fi
file=$1
if [ ! -f "$file" ]; then
echo "Error: $file not found."
exit 1;
fi
partSizeInMb=$2
fileSizeInMb=$(du -m "$file" | cut -f 1)
parts=$((fileSizeInMb / partSizeInMb))
if [[ $((fileSizeInMb % partSizeInMb)) -gt 0 ]]; then
parts=$((parts + 1));
fi
checksumFile=$(mktemp -t s3md5.XXXXXXXXXXXXX)
for (( part=0; part<$parts; part++ ))
do
skip=$((partSizeInMb * part))
$(dd bs=1M count=$partSizeInMb skip=$skip if="$file" 2> /dev/null | md5sum >> $checksumFile)
done
etag=$(echo $(xxd -r -p $checksumFile | md5sum)-$parts | sed 's/ --/-/')
echo -e "${1}\t${etag}"
rm $checksumFile
操作系统版本:
#!/bin/bash
if [ $# -ne 2 ]; then
echo "Usage: $0 file partSizeInMb";
exit 0;
fi
file=$1
if [ ! -f "$file" ]; then
echo "Error: $file not found."
exit 1;
fi
partSizeInMb=$2
fileSizeInMb=$(du -m "$file" | cut -f 1)
parts=$((fileSizeInMb / partSizeInMb))
if [[ $((fileSizeInMb % partSizeInMb)) -gt 0 ]]; then
parts=$((parts + 1));
fi
checksumFile=$(mktemp -t s3md5)
for (( part=0; part<$parts; part++ ))
do
skip=$((partSizeInMb * part))
$(dd bs=1m count=$partSizeInMb skip=$skip if="$file" 2>/dev/null | md5 >>$checksumFile)
done
echo $(xxd -r -p $checksumFile | md5)-$parts
rm $checksumFile
以下是我用Python编写的比较本地文件校验和与S3 ETag的代码。
def md5_checksum(filename):
m = hashlib.md5()
with open(filename, 'rb') as f:
for data in iter(lambda: f.read(1024 * 1024), b''):
m.update(data)
return m.hexdigest()
def etag_checksum(filename, chunk_size=8 * 1024 * 1024):
md5s = []
with open(filename, 'rb') as f:
for data in iter(lambda: f.read(chunk_size), b''):
md5s.append(hashlib.md5(data).digest())
m = hashlib.md5(b"".join(md5s))
print('{}-{}'.format(m.hexdigest(), len(md5s)))
return '{}-{}'.format(m.hexdigest(), len(md5s))
def etag_compare(filename, etag):
et = etag[1:-1] # strip quotes
print('et',et)
if '-' in et and et == etag_checksum(filename):
return True
if '-' not in et and et == md5_checksum(filename):
return True
return False
def main():
session = boto3.Session(
aws_access_key_id=s3_accesskey,
aws_secret_access_key=s3_secret
)
s3 = session.client('s3')
obj_dict = s3.get_object(Bucket=bucket_name, Key=your_key)
etag = (obj_dict['ETag'])
print('etag', etag)
validation = etag_compare(filename,etag)
print(validation)
etag_checksum(filename, chunk_size=8 * 1024 * 1024)
return validation
etag_checksum
函数时,我遇到了文件大小小于 chunk_size
的问题。一个简单的文件大小测试 (os.path.getsize(filename) < chunk_size
) 可以解决这个问题,如果其他人也遇到了这个问题,可以尝试这种方法。在这种情况下,哈希值是 hashlib.md5(f.read())
。 - KingBugAndTheCodeWizardGetObjectAttributes
:
新功能 - Amazon S3的附加Checksum算法 | AWS新闻博客
Checksum检索 - 新的
GetObjectAttributes
函数返回对象的校验和以及(如果适用)每个部分的校验和。
该函数支持SHA-1、SHA-256、CRC-32和CRC-32C来检查传输的完整性。
更新:看起来,虽然这种GetObjectAttributes
方法在许多情况下都有效,但在某些情况下,如控制台上传,校验和是基于16 MB块计算的。请参见例如检查对象完整性:
对于那些花费时间搜索为什么在S3中md5与ETag不同的人来说。
ETag将根据数据块计算并连接所有md5哈希以再次生成md5哈希,并在末尾保留数据块数。
这里是生成哈希的C#版本。
string etag = HashOf("file.txt",8);
private string HashOf(string filename,int chunkSizeInMb)
{
string returnMD5 = string.Empty;
int chunkSize = chunkSizeInMb * 1024 * 1024;
using (var crypto = new MD5CryptoServiceProvider())
{
int hashLength = crypto.HashSize/8;
using (var stream = File.OpenRead(filename))
{
if (stream.Length > chunkSize)
{
int chunkCount = (int)Math.Ceiling((double)stream.Length/(double)chunkSize);
byte[] hash = new byte[chunkCount*hashLength];
Stream hashStream = new MemoryStream(hash);
long nByteLeftToRead = stream.Length;
while (nByteLeftToRead > 0)
{
int nByteCurrentRead = (int)Math.Min(nByteLeftToRead, chunkSize);
byte[] buffer = new byte[nByteCurrentRead];
nByteLeftToRead -= stream.Read(buffer, 0, nByteCurrentRead);
byte[] tmpHash = crypto.ComputeHash(buffer);
hashStream.Write(tmpHash, 0, hashLength);
}
returnMD5 = BitConverter.ToString(crypto.ComputeHash(hash)).Replace("-", string.Empty).ToLower()+"-"+ chunkCount;
}
else {
returnMD5 = BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", string.Empty).ToLower();
}
stream.Close();
}
}
return returnMD5;
}
最简单的方法是在上传这些文件到你的存储桶之前,将校验和自己设置为元数据:
ObjectMetadata md = new ObjectMetadata();
md.setContentMD5("foobar");
PutObjectRequest req = new PutObjectRequest(BUCKET, KEY, new File("/path/to/file")).withMetadata(md);
tm.upload(req).waitForUploadResult();
ObjectMetadata md2 = s3Client.getObjectMetadata(BUCKET, KEY);
System.out.println(md2.getContentMD5());
这是一个有关AWS SDK for Java的问题。该问题解决了S3客户端在上传大文件时可能会崩溃的问题。此外,还修复了一些Javadoc错误和其他小问题。建议用户升级到最新版本以获取更好的性能和稳定性。
MD5是一个已弃用的算法,不受AWS S3支持,但您可以通过使用--checksum-algorithm
上传文件来获取SHA256校验和,如下所示:
aws s3api put-object --bucket picostat --key nasdaq.csv --body nasdaq.csv --checksum-algorithm SHA256
这将返回类似于以下的输出:
{
"ETag": "\"25f798aae1c15d44a556366b24d85b6d\"",
"ChecksumSHA256": "TEqQVO6ZsOR9FEDv3ofP8KDKbtR02P6foLKEQYFd+MI=",
"ServerSideEncryption": "AES256"
}
shasum -a 256 nasdaq.csv | cut -f1 -d\ | xxd -r -p | base64
将CSV文件的引用替换为您自己的引用,并将桶名称更改为您自己的名称。
每当您想要检索校验和时,可以运行:
aws s3api get-object-attributes --bucket picostat --key nasdaq.csv --object-attributes "Checksum"
s3cmd ls --list-md5 s3://bucket_of_mine/
我已经成功地使用了以下方法。这里我提供一个带注释的Python片段。
假设我们想要获取存储在S3中的对象的MD5校验和,并且该对象是使用分块上传过程加载的。在S3中与对象一起存储的ETag值不是我们想要的MD5校验和。可以使用以下Python命令来流式传输对象的二进制数据,而无需下载或打开对象文件,以计算所需的MD5校验和。请注意,此方法假定已建立到包含对象的S3帐户的连接,并且已导入boto3和hashlib模块:
#
# specify the S3 object...
#
bucket_name = "raw-data"
object_key = "/date/study-name/sample-name/file-name"
s3_object = s3.Object(bucket_name, object_key)
#
# compute the MD5 checksum for the specified object...
#
s3_object_md5 = hashlib.md5(s3_object.get()['Body'].read()).hexdigest()
这种方法适用于存储在S3中的所有对象(即,使用或不使用分段上传过程加载的对象)。