Flask - 如何获取请求中每个文件的大小?

3 投票
2 回答
6489 浏览
提问于 2025-04-17 20:23

我在一个网站上处理文件上传,后端使用的是Flask。所有文件都是通过一个POST请求从客户端发送到服务器的,我用requestgetlist()方法来逐个处理这些文件,然后用for循环来遍历它们。

if request.method == 'POST':
    files = request.files.getlist('f[]')

问题是我想限制每个上传文件的大小为50MB,但我觉得MAX_CONTENT_LENGTH是限制整个请求的大小。有没有办法让我检查request对象中每个文件的大小,如果某个文件太大就拒绝它?用户可以上传一定数量的文件,但每个文件都必须小于50MB。

2 个回答

7

这里有两条信息可以帮助你:

  1. 有时候,Content-Length这个头部会被设置;解析这个头部可以确保它和实际上传的数据是准确的。如果是这样,你可以通过FileStorage.content_length属性来获取这个值。

  2. 上传的文件是文件对象(可能是临时文件或者内存中的文件对象);你可以直接使用file.seek()file.tell()来确定它们的大小,而不需要读取整个文件。可能会有一种情况是内存中的文件对象不支持寻址,这时候你可以把整个文件读取到内存中,因为它的大小应该不会太大,不需要在磁盘上创建临时文件。

综合起来,测试单个文件大小的最佳方法是:

def get_size(fobj):
    if fobj.content_length:
        return fobj.content_length

    try:
        pos = fobj.tell()
        fobj.seek(0, 2)  #seek to end
        size = fobj.tell()
        fobj.seek(pos)  # back to original position
        return size
    except (AttributeError, IOError):
        pass

    # in-memory file object that doesn't support seeking or tell
    return 0  #assume small enough

然后在你的循环中:

for fobj in request.files.getlist('f[]'):
    if get_size(fobj) > 50 * (1024 ** 2):
        abort(413)  # request entity too large

这样就可以完全避免把数据读入内存。

-4

把最大内容长度(MAX_CONTENT_LENGTH)设置为一个合理的值,这个值应该是所有文件总大小的上限。然后在处理每个文件之前,先检查一下文件的大小。

if request.method == 'POST':
       files = request.files.getlist('f[]')
       for f in files:
          if len(f.read()) < (50 * 1024 * 1024):
                # do something

撰写回答