zipfile write не находит файлы в gcloud - PullRequest
0 голосов
/ 17 января 2020

Я пытаюсь заархивировать несколько файлов из Google Storage.

ZIP-файл Python не находит файлы в gcloud, только в проекте.

Как я могу сделать для своего кода найти файлы в gcloud?

    zip_buffer = io.BytesIO()
    with zipfile.ZipFile(zip_buffer, 'w') as zip_file:
        for revenue in revenues:
        # queryset with files a lot, so, for a each file, add in zip
            t = tempfile.NamedTemporaryFile()
            t.write(revenue.revenue.name)
            if revenue.revenue.name:
                t.seek(0)
                with default_storage.open(revenue.revenue.name, "r") as file_data:
                    zip_file.write(file_data.name, compress_type=zipfile.ZIP_DEFLATED)
                    # the code dont pass from this part
                t.close()
    response = HttpResponse(content_type='application/x-zip-compressed')
    response['Content-Disposition'] = 'attachment; filename=my_zip.zip'
    response.write(zip_buffer.getvalue())
    return response

В этой части я пишу файл, который я открыл из gcloud, но останавливаюсь внутри функции:

def write(self, filename, arcname=None, compress_type=None):
    """Put the bytes from filename into the archive under the name
    arcname."""
    if not self.fp:
        raise RuntimeError(
              "Attempt to write to ZIP archive that was already closed")
    st = os.stat(filename) 
    # when I try find the file, the command os.stat search in project, not in gcloud 

the "os.stat ( имя файла) "поиск файла в проекте, как я могу найти в gcloud?

Ответы [ 2 ]

0 голосов
/ 04 февраля 2020

окончательный код:

zip_buffer = io.BytesIO()
base_path = '/home/everton/compressedfiles/'
fiscal_compentecy_month = datetime.date(int(year), int(month), 1)
revenues = CompanyRevenue.objects.filter(company__pk=company_id, fiscal_compentecy_month=fiscal_compentecy_month)

if revenues.count() > 0:
    path = base_path + str(revenues.first().company.user.pk) + "/"
    zip_name = "{}-{}-{}-{}".format(revenues.first().company.external_id, revenues.first().company.external_name, month, year)

    for revenue in revenues:
        filename = revenue.revenue.name.split('revenues/')[1]
        if not os.path.exists(path):
            os.makedirs(path)
        with open(path + filename, 'wb+') as file:
            file.write(revenue.revenue.read())
        file.close()

    with zipfile.ZipFile(zip_buffer, 'w') as zip_file:
        for file in os.listdir(path):
            zip_file.write(path + file, compress_type=zipfile.ZIP_DEFLATED)
    zip_file.close()

    response = HttpResponse(content_type='application/x-zip-compressed')
    response['Content-Disposition'] = 'attachment; filename={}.zip'.format(zip_name)
    response.write(zip_buffer.getvalue())
    shutil.rmtree(path)
    return response
0 голосов
/ 27 января 2020

Я опубликую свои выводы как ответ, так как я хотел бы прокомментировать несколько вещей.

Я понял:

  1. У вас есть Python библиотека zipfile это используется для работы с файлами ZIP.
  2. Вы ищете файлы локально и добавляете один за другим в файл ZIP.
  3. Вы хотели бы сделать это также для файлов, расположенных в Google Cloud Storage корзина. Но он не может найти файлы.

Если я неправильно понял сценарий варианта использования, пожалуйста, уточните подробнее в комментарии.

Однако, если это именно то, что вы пытаясь сделать, то это не поддерживается. В вопросе StackOverflow - Сжатие файлов, сохраненных в облачном хранилище Google , указано, что сжатие файлов, которые уже находятся в Google Cloud Storage , невозможно. Решение в этом вопросе состоит в том, чтобы подписаться на вновь созданные файлы, а затем загрузить их локально, сжать их и перезаписать в GCS. Как видите, вы можете перечислить файлы или просмотреть файлы, хранящиеся в GCS, но сначала вам нужно загрузить их, чтобы иметь возможность их обрабатывать.

Обход

Поэтому в вашем сценарии использования я бы рекомендовал следующий обходной путь, используя клиентский API Python:

  1. Вы можете использовать Список объектов Python API, чтобы получить все объекты из GCS.
  2. Затем вы можете использовать Загрузка объектов Python API , для загрузки объектов локально.
  3. Как только объекты расположены в локальном каталоге, вы можете использовать библиотеку zipfile Python, чтобы объединить их вместе, как вы уже это делаете.
  4. Затем объекты архивируются и, если вам больше не нужны загруженные объекты, вы можете удалить их с помощью os.remove("downloaded_file.txt").
  5. На случай, если вам понадобится сжатый ZIP-файл в Google Cloud Хранилище , затем вы можете использовать API Uploading Python для загрузки ZIP-файла в корзину GCS.

Как я уже упоминал выше, обработка файлов (например, добавление их в ZIP-файлы и т. Д. c.) непосредственно в Google Cloud Storage корзина, не поддерживается. Вы должны сначала загрузить их локально, чтобы сделать это. Я надеюсь, что мой обходной путь будет вам полезен.

ОБНОВЛЕНИЕ

Как я уже упоминал выше, архивирование файлов, пока они находятся в корзине GCS, не поддерживается. Поэтому я подготовил для вас рабочий пример в Python о том, как использовать обходной путь.

ПРИМЕЧАНИЕ. Поскольку я не профессионал в работе с командами os с Python библиотека, и я не знаком с библиотекой zipfile, возможно, есть лучший и более эффективный способ добиться этого. Однако код, который можно найти в этой ссылке на GitHub , выполняет следующие процедуры:

  • В разделе #Public variables: изменяется BUCKET_NAME на соответствующее имя корзины и выполните сценарий python в Google Cloud Shell . Cloud Shell
  • Теперь моя структура сегмента выглядит следующим образом:
gs://my-bucket/test.txt
gs://my-bucket/test1.txt
gs://my-bucket/test2.txt
gs://my-bucket/directory/test4.txt

При выполнении команды приложение выполняет следующее:

  1. Получит путь к месту выполнения скрипта. например, /home/username/myapp.
  2. Он создаст временный каталог в этом каталоге, например, /home/username/myapp/temp
  3. Он будет перебирать все файлы, расположенные в указанной вами корзине, и будет загружать их локально внутри этого временного каталога.

    ПРИМЕЧАНИЕ. Если файл в корзине находится в каталоге, он просто загрузит файл, вместо того, чтобы снова создавать этот подкаталог. Вы можете изменить код, чтобы позже он работал так, как вам нужно.

  4. Таким образом, новые загруженные файлы будут выглядеть следующим образом:
/home/username/myapp/temp/test.txt
/home/username/myapp/temp/test1.txt
/home/username/myapp/temp/test2.txt
/home/username/myapp/temp/test4.txt
После этого код заархивирует все эти файлы в новый zipedFile.zip, который будет находиться в том же каталоге с выполненным вами сценарием main.py. Когда этот шаг будет выполнен, сценарий удалит каталог /home/username/myapp/temp/ со всем его содержимым.

Как я уже упоминал выше, после локального выполнения сценария вы должны возможность видеть файлы main.py и zipedFile.zip со всеми заархивированными файлами из корзины GCS. Теперь вы можете взять идею реализации и изменить ее в соответствии с потребностями вашего проекта.

...