【问题标题】:Python3 Flask upload file in server memoryPython3 Flask 在服务器内存中上传文件
【发布时间】:2015-04-03 23:50:27
【问题描述】:

我在 Python3 中使用 Flask 作为网络服务器,并且正在使用 Flask 的上传功能。将文件上传到服务器会生成 werkzeug.datastructures.FileStorage 对象。

我需要这个文件的功能之一,也需要能够从路径对象打开文件,所以目前我使用的是open(file_to_open)。如果可能的话,我想避免将上传的文件写入临时文件,只是为了再次读取它。所以我的问题包括两部分:

1:是否可以将此 FileStorage 对象“翻译”为文件对象?

2:如果是这样,这是否也适用于当前代码 (open(file_to_open))?

【问题讨论】:

  • 你真的需要open(file_to_open)吗?因为FileStorage对象本身提供了文件API,所以直接使用即可。如果您需要再次读取文件,只需致电uploaded_file.seek(0)
  • 我需要一个能够从磁盘、使用路径以及从内存对象读取文件的函数。如果这意味着替换open(file_to_open),那很好,只要函数readfile(file)可以将文件作为路径并且文件/任何东西FileStorage可以转换为
  • 为什么不是一个只从文件对象中读取的函数呢?然后你可以给它一个FileStorage 对象(readfile(uploaded_file))它会工作。如果您需要将该函数用于磁盘上的文件,请使用readfile(open(filename)) 调用它。函数根据其类型用两种方式解释一个参数(所以readfile(filename)readfile(open(filename))具有相同的效果)设计得不是很好。

标签: python file python-3.x memory flask


【解决方案1】:

传入的文件上传确实显示为FileStorage 对象。但是,这并不一定意味着涉及到实际的物理文件。

解析文件对象时,Werkzeug 使用 stream_factory() 可调用来生成文件对象。默认实现只为 500kb 及以上的文件创建一个实际的物理文件,以避免占用内存。

对于较小的文件,使用内存中的文件对象。

我不会篡改这种安排;由于它现在可以正常工作,因此问题得到了透明处理,并且仅在文件上传会过多占用您的内存时才涉及您的硬盘。

相反,我会将该函数更改为不需要文件名和/或接受文件对象。

如果你的函数只能将路径作为字符串,你可以通过内省.stream属性来查看是否需要读取文件:

from werkzeug._compat import BytesIO

filename = data = None
if file_upload.filename is None:
    data = file_upload.read()  # in-memory stream, so read it out.
else:
    filename = file_upload.filename

【讨论】:

  • 最后我用了类似的方法。我更改了函数,因此它不会在方法中执行open(file_to_open)。相反,现在我可以通过StringIO((file.stream.read()).decode("utf-8"))open(file_to_open) 而不仅仅是file_to_open。在这种情况下,我很幸运它是一个字符串,但我想正如你所说,使用 BytesIO,你可以随心所欲地制作它。我会将此标记为已接受的答案,但可以添加“替代”部分吗?
  • @pidgey:您可以使用自己的_get_file_stream 实现创建Request 工厂的子类,以将default_stream_factory 替换为您自己的,然后将其设置为Flask.request_class attribute。也许吧。
  • @pidgey:但是,我的回答中已经提到了您的“类似”方法。 :-) 相反,我会将该函数更改为不需要文件名和/或接受文件对象。.
  • 当我将来偶然发现这些问题时,这对于“更难”的问题可能是一个好主意。谢谢你的提示。现在,StringIO 可以解决问题,因为它始终是字符串,但如果我在图像的上下文中需要它,我会考虑你的评论
  • @pidgey:这是 Python 3 吗?因为您可以用TextIOWrapper() object 包装BytesIO 以提供来自二进制“文件”的解码数据。
【解决方案2】:

您可以将上传的文件存储到tmpfs。这样,它们仍然是常规文件,无法使用open() 打开。

【讨论】:

  • 我知道这一点,但这不会跨平台(Windows)工作,对吧?另外,它并不是真正的 python 特定解决方案(您必须创建一个文件系统并指向它,因此任何更改都必须导致代码更改)
  • 是的,这个解决方案不是“pythonic”,移植到其他平台可能会有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-07
  • 2015-09-14
  • 2013-11-28
  • 1970-01-01
  • 2014-01-11
  • 1970-01-01
相关资源
最近更新 更多