【问题标题】:How to decompress a FileStorage object over gzip in Flask如何在 Flask 中通过 gzip 解压缩 FileStorage 对象
【发布时间】:2020-06-21 17:14:43
【问题描述】:

我正在通过 HTTP 多部分/表单数据 POST 请求向我的烧瓶应用程序发送一个压缩文件(使用 gzip 压缩)。该请求正常工作,当我将密钥的值打印到控制台时,它会打印:<FileStorage: 'compressed.zip' ('application/zip')>。这是使用 Windows zip 压缩的压缩文件,但将使用 application/gzip 类型进行压缩。压缩的.zip 文件的密钥称为compressed。我的问题是如何解压缩 gzip 文件,然后将 FileStorage 对象存储到后端的特定路径?这是我目前拥有的代码:

from flask import request, Blueprint, make_response
import gzip
blueprint = Blueprint("blueprint", __name__)

@blueprint.route("/compressed-post", methods=["POST"])
def compressed_post():
    if request.method == "POST":
        file = request.files["compressed"]
        print(file)
        return make_response("", 200)
    else:
        return make_response("", 400)

【问题讨论】:

  • 所以你想解压gzip文件并将内容(压缩文件中的所有文件)放在一个filestorage中?
  • 是的,这就是我想要做的。
  • 我很快就会上传一个答案。所以只需将 zip 文件中的所有文件放在某个文件夹中,file 包含压缩文件对吗?
  • 是的,但正如我之前提到的,file 是一个 FileStorage 对象,所以我不知道如何处理该数据类型。
  • @Patch 你要上传答案吗?

标签: python-3.x flask httprequest gzip file-storage


【解决方案1】:

鉴于您的代码 sn-p...

@blueprint.route("/compressed-post", methods=["POST"])
def compressed_post():
    if request.method == "POST":
        file = request.files["compressed"]

...您只需将file._file 传递给ZipFile 构造函数,因为ZipFile 需要一个类似文件的对象(或完整路径,我们这里没有,因为文件是尚未保存到磁盘)。

然后,您可以使用ZipFiles extractAll 方法将文件提取到您喜欢的路径。

另见

https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile.extractall

所以,完整的代码应该是这样的:

from flask import request, Blueprint, make_response
import gzip
from zipfile import ZipFile
blueprint = Blueprint("blueprint", __name__)

@blueprint.route("/compressed-post", methods=["POST"])
def compressed_post():
    if request.method == "POST":
        file = request.files["compressed"]
        zip_handle = ZipFile(file._file)
        zip_handle.extractall(CHOOSE_YOUR_PATH)
        zip_handle.close()
        return make_response("", 200)
    else:
        return make_response("", 400)
        

ZipFile 也有一个上下文管理器,如果您更喜欢 with 语法。

请注意:file._file 中的_ 表示_file 不是公共接口的一部分,将来可能会更改。

【讨论】:

  • 我很快就会尝试这个解决方案。我对你在_file 中所说的_ 感到困惑。这意味着它不是公共界面的一部分,以及使用_file 可以创建什么样的问题?
  • 这在评论中很难解释。通常,库的作者确保不更改库用户将使用的变量和函数名称。例如ZipFile 的名称不会轻易更改,因为许多人依靠此名称保持不变。这不适用于以下划线开头的名称。虽然你也可以使用它们,就像这里_file,库的作者可能会在没有“不好”感觉的情况下更改它,因为下划线是“请不要使用”的指示符。不要太担心!我非常有信心在未来几年不会发生变化。
  • 哦,好的,我现在明白了。开发人员通常会在变更日志中声明对他们创建的开源库的任何更改,对吗?如果他们有文档(我希望他们有),那么他们会说明目前所做的更改,这不是一个大问题。感谢您清除它!
【解决方案2】:

尝试使用以下方法:

from flask import request, Blueprint, make_response
from zipfile import ZipFile
import gzip
blueprint = Blueprint("blueprint", __name__)

@blueprint.route("/compressed-post", methods=["POST"])
def compressed_post():
    if request.method == "POST":
        file = request.files["compressed"]
        print(file)
        file_name = file.filename
        with ZipFile(file_name, 'r') as zip: 
            # printing all the contents of the zip file 
            zip.printdir() 
  
            # extracting all the files 
            print('Extracting all the files now...') 
            zip.extractall(<path_to_destination_dir>) 
            print('Done!')
        
        return make_response("", 200)
    else:
        return make_response("", 400)

有关 zip 的更多详细信息,请参阅:ZipFileextractall()

有关 FileStorage 对象的更多详细信息,请参阅此内容:FileStorage

如果您需要更多信息来存储 FileStorage 对象: 将文件保存到目标路径或文件对象。如果目标是文件对象,您必须在调用后自行关闭它。缓冲区大小是复制过程中内存中保存的字节数。默认为 16KB。

看到这个:save

希望对你有帮助。

【讨论】:

  • 对于 save() 函数,如果我不知道缓冲区大小,假设它大于默认的 16KB 怎么办?如果可能存在该漏洞,我不想溢出缓冲区。
  • 另外,我完全使用了您的代码,并在这行代码with ZipFile(file_name, 'r') as zip: 的响应中获得了带有file_name 变量的FileNotFoundError。
  • 你知道我为什么会收到这个错误吗?我无法使用 save() 函数保存文件,因为它是一个 zip 文件,所以这可能是抛出错误的原因,因为它没有保存在当前目录中,那么我该如何解决这个问题?
  • 这不起作用,因为filen_ame 只是一个文件名,而不是完整的路径。对于几种可能的解决方案之一,请参阅我的答案。
猜你喜欢
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多