Сложность сравнения сгенерированного и облачного хранилища Google при условии контрольных сумм CRC32c
Я пытаюсь получить CRC32c
контрольная сумма в моем локальном файле, чтобы я мог сравнить ее с blob.crc32c, предоставленным библиотекой gcloud. Google говорит, что я должен использовать модуль crcmod, чтобы вычислить CRC32c
хеши моих данных.
modifiedFile.txt
уже загружен из корзины Google Cloud Storage в мою локальную файловую систему.
Цель здесь состоит в том, чтобы установить should_download
истинно, только если modifiedFile.txt
имеет другой CRC32c
на моем локальном клиенте против моего удаленного сервера. Как мне заставить их генерировать соответствия CRC32c
в случае, если моя локальная файловая система и мой BLOB-объект gcloud имеют одинаковое содержимое?
from crcmod import PredefinedCrc
from gcloud import storage
# blob is a gcloud Blob object
should_download = True
with open('modifiedFile.txt') as f:
hasher = PredefinedCrc('crc-32c')
hasher.update(f.read())
crc32c = hasher.digest()
print crc32c # \207\245.\240
print blob.crc32c # CJKo0A==
should_download = crc32c != blob.crc32c
К сожалению, в настоящее время он всегда терпит неудачу, так как я не знаю, как сравнить контрольную сумму, которую я строю crcmod
к атрибуту, который я вижу в соответствии Blob
объект.
3 ответа
Вот пример md5 и crc32c для общедоступного архива gsutil:
$ gsutil ls -L gs://pub/gsutil.tar.gz | grep Hash
Hash (crc32c): vHI6Bw==
Hash (md5): ph7W3cCoEgMQWvA45Z9y9Q==
Я скопирую его локально для работы с:
$ gsutil cp gs://pub/gsutil.tar.gz /tmp/
Copying gs://pub/gsutil.tar.gz...
Downloading file:///tmp/gsutil.tar.gz: 2.59 MiB/2.59 MiB
Значения CRC обычно отображаются как 32-разрядные целые числа без знака. Чтобы преобразовать это:
>>> import base64
>>> import struct
>>> struct.unpack('>I', base64.b64decode('vHI6Bw=='))
(3161602567,)
Чтобы получить то же самое из библиотеки crcmod:
>>> file_bytes = open('/tmp/gsutil.tar.gz', 'rb').read()
>>> import crcmod
>>> crc32c = crcmod.predefined.Crc('crc-32c')
>>> crc32c.update(file_bytes)
>>> crc32c.crcValue
3161602567L
Если вы хотите преобразовать значение из crcmod в тот же формат base64, который используется gcloud/gsutil:
>>> base64.b64encode(crc32c.digest())
'vHI6Bw=='
В 2022 году мне все еще было трудно найти окончательный ответ. Вот что я придумал, похоже, работает с большими файлами.
import google_crc32c
import collections
def generate_file_crc32c(path, blocksize=2**20):
"""
Generate a base64 encoded crc32c checksum for a file to compare with google cloud storage.
Returns a string like "4jvPnQ=="
Compare with a google storage blob instance:
blob.crc32c == generate_file_crc32c("path/to/local/file.txt")
"""
crc = google_crc32c.Checksum()
read_stream = open(path, "rb")
collections.deque(crc.consume(read_stream, blocksize), maxlen=0)
read_stream.close()
return base64.b64encode(crc.digest()).decode("utf-8")
Из связанной документации: "Контрольная сумма CRC32c, как описано в RFC 4960, Приложение B; закодирована с использованием base64 в порядке старших байтов"
Похоже, вы не декодируете строку base64.
Если вы работаете на компьютере с Windows, вам нужно открыть текстовый файл в двоичном режиме.