У меня есть ведро s3, в котором нет большого количества zip файлов, имеющих размер в GB. Мне нужно рассчитать всю длину данных zip файлов. Я прохожу через boto3, но не понял. Я не уверен, может ли он напрямую читать zip файл или нет, но у меня есть process-
Примечание. Ничего не следует загружать на локальное хранилище. Весь процесс продолжается с S3 до S3. Любые предложения приветствуются.
То, что вы хотите сделать, невозможно, как объяснил ответ Джона Ротенштейна. Вам необходимо загрузить zipfile - не обязательно в локальное хранилище, но, по крайней мере, в локальную память, используя вашу локальную пропускную способность. Нет способа запустить какой-либо код на S3.
Тем не менее, возможно, есть способ получить то, что вы действительно здесь, в любом случае.
Если бы вы могли просто загрузить, скажем, 8 КБ файла, а не всего 5 ГБ, это было бы достаточно хорошо? Если это так - и если вы готовы немного поработать, тогда вам повезло. Что делать, если вам нужно было скачать, скажем, 1 МБ, но может сделать намного меньше работы?
Если 1MB не звучит слишком плохо, и вы готовы немного взломать:
Единственное, что вы хотите, это количество файлов в zipfile. Для zipfile вся эта информация доступна в центральном каталоге, очень маленьком фрагменте данных в самом конце файла.
И если у вас есть весь центральный каталог, даже если вам не хватает остальной части файла, zipfile
модуль в stdlib справится с этим просто отлично. Это не документировано, но, по крайней мере, в версиях, включенных в последние версии CPython и PyPy 3.x, это определенно будет.
Итак, что вы можете сделать, так это:
HEAD
чтобы получить только заголовки. (В boto
вы делаете это с помощью head_object
.)Content-Length
.GET
с заголовком Range
чтобы загружать, скажем, size-1048576
до конца. (В boto
, я считаю, вам, возможно, придется вызвать get_object
вместо одного из методов download*
, и вам нужно get_object
форматировать значение заголовка Range
.) Теперь, предполагая, что у вас есть последний 1 МБ в буфере buf
:
z = zipfile.ZipFile(io.BytesIO(buf))
count = len(z.filelist)
Обычно 1 МБ более чем достаточно. Но как насчет того, когда это не так? Ну, здесь, где все становится немного взломанным. Модуль zipfile
знает, сколько еще байтов вам нужно, но единственное место, которое оно дает вам, в тексте описания исключения. Так:
try:
z = zipfile.ZipFile(io.BytesIO(buf))
except ValueError as e:
m = re.match(r'negative seek value -(\d+)', z.args[0])
if not m:
raise
extra = int(m.group(1))
# now go read from size-1048576-extra to size-1048576, prepend to buf, try again
count = len(z.filelist)
Если 1MB уже звучит как слишком большая пропускная способность, или вы не хотите полагаться на недокументированное поведение модуля zipfile
, вам просто нужно немного поработать.
Почти в каждом случае вам даже не нужен весь центральный каталог, а всего total number of entries
полей total number of entries
в end of central directory record
- даже меньший фрагмент данных в самом конце центрального каталога.
Итак, делайте то же самое, что и выше, но читайте только последние 8 КБ, а не последние 1 МБ.
А затем, основываясь на спецификации формата zip, напишите свой собственный синтаксический анализатор.
Конечно, вам не нужно писать полный парсер или даже близко к нему. Вам просто нужно достаточно, чтобы иметь дело с полями от total number of entries
до конца. Все из них являются полями фиксированного размера, за исключением zip64 extensible data sector
и/или .ZIP file comment
.
Иногда (например, для zip файлов с огромными комментариями) вам нужно будет прочитать больше данных, чтобы получить счет. Это должно быть довольно редко, но если по какой-то причине это становится более распространенным с вашими zip файлами, вы можете просто изменить, что 8192 догадывается о чем-то большем.
Body
возвращаемое get_object
представляет собой [ botocore.request.StreamingBody
] (botocore.response.StreamingBody), так что вы посмотрите это в документах и узнаете, как считывать из него буфер. И что бы вы ни читали, вот что такое buf
.
Это невозможно.
Вы можете загружать файлы на Amazon S3, и вы можете скачивать файлы. Вы можете запросить список объектов и получить метаданные об объектах. Однако Amazon S3 не обеспечивает вычисление, например сжатие/декомпрессию.
Вам нужно будет написать программу, которая:
Это, вероятно, лучше всего сделать на экземпляре Amazon EC2, который будет иметь доступ с низкой задержкой к Amazon S3. Вы можете сделать это с помощью функции AWS Lambda, но она имеет ограничение на 500 МБ дискового хранилища и 5 минут выполнения, что не похоже на вашу ситуацию.
Если вы особенно умны, вы можете загрузить часть каждого zip файла ("ranged get") и интерпретировать заголовок zipfile, чтобы получить список файлов и их размеры, что позволяет избежать загрузки всего файла.