Сложность сравнения сгенерированного и облачного хранилища 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, вам нужно открыть текстовый файл в двоичном режиме.

Другие вопросы по тегам