Nếu tôi có các tệp hiện có trên S3 của Amazon, thì cách dễ nhất để lấy md5sum của chúng mà không cần phải tải tệp xuống là gì?
Cảm ơn
Nếu tôi có các tệp hiện có trên S3 của Amazon, thì cách dễ nhất để lấy md5sum của chúng mà không cần phải tải tệp xuống là gì?
Cảm ơn
Câu trả lời:
Tài liệu của AWS ETag
nói:
Thẻ thực thể là một hàm băm của đối tượng. ETag chỉ phản ánh những thay đổi đối với nội dung của một đối tượng, không phản ánh siêu dữ liệu của nó. ETag có thể có hoặc không phải là bản tóm tắt MD5 của dữ liệu đối tượng. Việc có hay không tùy thuộc vào cách đối tượng được tạo ra và cách nó được mã hóa như mô tả bên dưới:
- Các đối tượng được tạo bởi Đối tượng PUT, Đối tượng POST hoặc thao tác Sao chép hoặc thông qua Bảng điều khiển quản lý AWS và được mã hóa bằng SSE-S3 hoặc văn bản rõ, có thẻ ETags là bản tóm tắt MD5 của dữ liệu đối tượng của chúng.
- Các đối tượng được tạo bởi Đối tượng PUT, Đối tượng POST hoặc thao tác Sao chép hoặc thông qua Bảng điều khiển quản lý AWS và được mã hóa bởi SSE-C hoặc SSE-KMS, có thẻ ETags không phải là bản tóm tắt MD5 của dữ liệu đối tượng của chúng.
- Nếu một đối tượng được tạo bởi thao tác Tải lên nhiều phần hoặc Sao chép một phần, ETag không phải là thông báo MD5, bất kể phương pháp mã hóa là gì.
Tham khảo: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html
ETag dường như không phải là MD5 để tải lên nhiều phần (theo nhận xét của Gael Fraiteur). Trong những trường hợp này, nó chứa một hậu tố là số trừ và một số. Tuy nhiên, ngay cả bit trước dấu trừ dường như không phải là MD5, mặc dù nó có cùng độ dài với MD5. Có thể hậu tố là số phần được tải lên?
aws s3 cp ...
Dưới đây là công việc để tôi so sánh tổng kiểm tra tệp cục bộ với s3 etag. Tôi đã sử dụng Python
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
your_key
giống như filename
?
etag_checksum
hàm này, tôi đã gặp sự cố với các tệp nhỏ hơn chunkt_size
. Một bài kiểm tra đơn giản về kích thước tệp ( os.path.getsize(filename) < chunk_size
) đã sửa lỗi này, trong trường hợp bất kỳ ai khác cũng gặp sự cố này. Trong trường hợp đó, hàm băm làhashlib.md5(f.read())
Đây là một câu hỏi rất cũ, nhưng tôi đã rất khó tìm thông tin bên dưới, và đây là một trong những nơi đầu tiên tôi có thể tìm thấy, vì vậy tôi muốn trình bày chi tiết để phòng trường hợp ai cần.
ETag là một MD5. Nhưng đối với các tệp được tải lên Multipart, MD5 được tính từ việc ghép các MD5 của mỗi phần được tải lên. Vì vậy, bạn không cần phải tính MD5 trong máy chủ. Chỉ cần lấy ETag và tất cả.
Như @EmersonFarrugia đã nói trong câu trả lời này :
Giả sử bạn đã tải lên một tệp 14MB và kích thước một phần của bạn là 5MB. Tính 3 tổng kiểm tra MD5 tương ứng với mỗi phần, tức là tổng kiểm tra của 5MB đầu tiên, 5MB thứ hai và 4MB cuối cùng. Sau đó, lấy tổng kiểm tra của nối của chúng. Vì tổng kiểm tra MD5 là biểu diễn hex của dữ liệu nhị phân, chỉ cần đảm bảo bạn lấy MD5 của phép ghép nhị phân được giải mã, không phải của phép nối được mã hóa ASCII hoặc UTF-8. Khi hoàn tất, hãy thêm dấu gạch ngang và số phần để lấy ETag.
Vì vậy, thứ duy nhất bạn cần là ETag và kích thước phần tải lên. Nhưng ETag có hậu tố -NumberOfParts. Vì vậy, bạn có thể chia kích thước cho hậu tố và lấy kích thước một phần. 5Mb là kích thước bộ phận tối thiểu và giá trị mặc định. Kích thước một phần phải là số nguyên, vì vậy bạn không thể nhận được những thứ như kích thước mỗi phần là 7,25Mb. Vì vậy, sẽ dễ dàng có được thông tin về kích thước bộ phận
Đây là một tập lệnh để thực hiện điều này trong osx, với một phiên bản Linux trong nhận xét: https://gist.github.com/emersonf/7413337
Tôi sẽ để lại cả hai tập lệnh ở đây trong trường hợp trang trên không còn truy cập được trong tương lai:
Phiên bản Linux:
#!/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
Phiên bản OSX:
#!/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
Đối với bất kỳ ai dành thời gian tìm kiếm xung quanh để tìm ra lý do tại sao md5 không giống với ETag trong S3.
ETag sẽ tính toán dựa trên phân đoạn dữ liệu và ghép tất cả md5hash để tạo lại băm md5 và giữ nguyên số lượng đoạn cuối.
Đây là phiên bản C # để tạo băm
string etag = HashOf("file.txt",8);
mã nguồn
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;
}
Tôi thấy rằng s3cmd có tùy chọn --list-md5 có thể được sử dụng với lệnh ls, ví dụ:
s3cmd ls --list-md5 s3://bucket_of_mine/
Hi vọng điêu nay co ich.
Tôi đã kiểm tra chéo jets3t và bảng điều khiển quản lý đối với MD5sum của các tệp được tải lên và ETag dường như bằng MD5sum. Bạn chỉ có thể xem các thuộc tính của tệp trong bảng điều khiển quản lý AWS:
Cách dễ nhất là tự đặt tổng kiểm tra làm siêu dữ liệu trước khi bạn tải các tệp này lên nhóm của mình:
ObjectMetadata md = new ObjectMetadata();
md.setContentMD5("foobar");
PutObjectRequest req = new PutObjectRequest(BUCKET, KEY, new File("/path/to/file")).withMetadata(md);
tm.upload(req).waitForUploadResult();
Giờ đây, bạn có thể truy cập các siêu dữ liệu này mà không cần tải xuống tệp:
ObjectMetadata md2 = s3Client.getObjectMetadata(BUCKET, KEY);
System.out.println(md.getContentMD5());
Điều này làm việc cho tôi. Trong PHP, bạn có thể so sánh tổng kiểm tra giữa tệp cục bộ với tệp amazon bằng cách sử dụng:
// get localfile md5
$checksum_local_file = md5_file ( '/home/file' );
// compare checksum between localfile and s3file
public function compareChecksumFile($file_s3, $checksum_local_file) {
$Connection = new AmazonS3 ();
$bucket = amazon_bucket;
$header = $Connection->get_object_headers( $bucket, $file_s3 );
// get header
if (empty ( $header ) || ! is_object ( $header )) {
throw new RuntimeException('checksum error');
}
$head = $header->header;
if (empty ( $head ) || !is_array($head)) {
throw new RuntimeException('checksum error');
}
// get etag (md5 amazon)
$etag = $head['etag'];
if (empty ( $etag )) {
throw new RuntimeException('checksum error');
}
// remove quotes
$checksumS3 = str_replace('"', '', $etag);
// compare md5
if ($checksum_local_file === $checksumS3) {
return TRUE;
} else {
return FALSE;
}
}
Đây là mã để lấy ETag S3 cho một đối tượng trong PowerShell được chuyển đổi từ c #.
function Get-ETag {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Path,
[Parameter(Mandatory=$true)]
[int]$ChunkSizeInMb
)
$returnMD5 = [string]::Empty
[int]$chunkSize = $ChunkSizeInMb * [Math]::Pow(2, 20)
$crypto = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
[int]$hashLength = $crypto.HashSize / 8
$stream = [System.IO.File]::OpenRead($Path)
if($stream.Length -gt $chunkSize) {
$chunkCount = [int][Math]::Ceiling([double]$stream.Length / [double]$chunkSize)
[byte[]]$hash = New-Object byte[]($chunkCount * $hashLength)
$hashStream = New-Object System.IO.MemoryStream(,$hash)
[long]$numBytesLeftToRead = $stream.Length
while($numBytesLeftToRead -gt 0) {
$numBytesCurrentRead = [int][Math]::Min($numBytesLeftToRead, $chunkSize)
$buffer = New-Object byte[] $numBytesCurrentRead
$numBytesLeftToRead -= $stream.Read($buffer, 0, $numBytesCurrentRead)
$tmpHash = $crypto.ComputeHash($buffer)
$hashStream.Write($tmpHash, 0, $hashLength)
}
$returnMD5 = [System.BitConverter]::ToString($crypto.ComputeHash($hash)).Replace("-", "").ToLower() + "-" + $chunkCount
}
else {
$returnMD5 = [System.BitConverter]::ToString($crypto.ComputeHash($stream)).Replace("-", "").ToLower()
}
$stream.Close()
$returnMD5
}
Đây là mã để có được băm MD5 theo năm 2017
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Base64;
public class GenerateMD5 {
public static void main(String args[]) throws Exception{
String s = "<CORSConfiguration> <CORSRule> <AllowedOrigin>http://www.example.com</AllowedOrigin> <AllowedMethod>PUT</AllowedMethod> <AllowedMethod>POST</AllowedMethod> <AllowedMethod>DELETE</AllowedMethod> <AllowedHeader>*</AllowedHeader> <MaxAgeSeconds>3000</MaxAgeSeconds> </CORSRule> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedHeader>*</AllowedHeader> <MaxAgeSeconds>3000</MaxAgeSeconds> </CORSRule> </CORSConfiguration>";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(s.getBytes());
byte[] digest = md.digest();
StringBuffer sb = new StringBuffer();
/*for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}*/
System.out.println(sb.toString());
StringBuffer sbi = new StringBuffer();
byte [] bytes = Base64.encodeBase64(digest);
String finalString = new String(bytes);
System.out.println(finalString);
}
}
Mã được nhận xét là nơi hầu hết mọi người hiểu sai khi đổi nó thành hex