Flask / Python: создание zip-файла по абсолютному пути не удается - такого файла или каталога нет - PullRequest
0 голосов
/ 08 февраля 2019

Я создаю плагин CKAN, который позволяет пользователям выбирать и загружать несколько ресурсов (файлов) с сервера базы данных.Я создал функцию просмотра фляги с некоторым кодом Python, который должен создать zip-файл с запрошенными ресурсами, но создание завершается неудачно с ошибкой «нет такого файла или каталога», даже если я даю абсолютный путь.

Кодоснован на этом , этом и этом сообщении, и для решения текущего вопроса я уже проверил здесь и здесь без особого успеха.

Код выглядит следующим образом:

import zipfile
import io

def download_multiple_resources():
    if request.method == "POST":

        memory_file = io.BytesIO()
        with zipfile.ZipFile(memory_file, "w", zipfile.ZIP_STORED) as zf:
            for res in request.form.values():
                zf.write(str(res), 'download.zip')

return send_file(memory_file, mimetype='application/zip', as_attachment=True, attachment_filename='download.zip')

Ресурсы выбираются пользователем через форму, которая отправляет запрос.Форма отправляет полный путь запрошенного файла, поэтому, если пользователь выбрал для загрузки testfile.txt, в приведенном выше коде значение res будет примерно таким, как http://localhost:5000/dataset/6192bb3b-6c4a/resource/dbe39d59-b938/download/testfile.txt.(в настоящее время тестирование выполняется на сервере, созданном в док-контейнере на моем компьютере)

Обратите внимание, что при вставке в мой браузер указанного выше пути можно без проблем получить доступ к файлу.Однако команда zf.write завершается неудачно с ошибкой «нет такого файла или каталога».

Есть идеи, что происходит не так?

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Оказывается, мое первоначальное предположение было правильным, и нужно только использовать writestr() вместо write(), в дополнение к чтению файла с запросом http.Вот полный рабочий код:

import zipfile
import io
import requests
from flask import request, send_file

def download_multiple_resources():
    if request.method == "POST":
        memory_file = io.Bytes.IO()
        with zipfile.ZipFile(memory_file, 'w', zipfile.ZIP_STORED) as zf:
            for res in request.form:
                f = requests.get(res, allow_redirects=True)
                zf.writestr('your_chosen_filename', f.content)
        memory_file.seek(0)

    return send_file(memory_file, mimetype='application/zip', as_attachment=True, attachment_filename="download.zip")

Дополнительное примечание: если вы работаете на внешнем сервере, например, я, и используете эту функцию, чтобы позволить зарегистрированным пользователям загружать файлы, убедитесь, что учетные данныепользователи передаются на звонок request.get() для авторизации загрузки.В моем случае это было сделано с помощью опции headers={'Authorization': user.apiKey}, но это может зависеть от вашей среды / приложения.

0 голосов
/ 08 февраля 2019

Вы говорите, что хотите получить доступ к ресурсу по его абсолютному пути, но вашим примером значения res является URL.

Я не думаю, что zipfile.ZipFile.write поддерживает это, так как добавление файла вzip-архив использует метаданные из файловой системы (временные метки и т. д.).Вам нужно будет либо получить доступ к ресурсу по его локальному пути, либо, если он недоступен из контейнера приложения, сначала загрузите его во временное местоположение.(Последний случай, конечно, лишит метаданные.)

...