cgi.FieldStorage如何存储文件?

Jus*_*nas 10 python cgi wsgi

所以我一直在玩原始的WSGI,cgi.FieldStorage和文件上传.我只是无法理解它如何处理文件上传.

起初它似乎只是将整个文件存储在内存中.而且我认为嗯,这应该很容易测试 - 一个大文件应该堵塞内存!..但事实并非如此.但是,当我请求文件时,它是一个字符串,而不是迭代器,文件对象或任何东西.

我已经尝试过阅读cgi模块的源代码并发现了一些关于临时文件的东西,但是它返回了一个怪异的字符串,而不是一个文件(类似的)对象!那么......它是如何运作的?!

这是我用过的代码:

import cgi
from wsgiref.simple_server import make_server

def app(environ,start_response):
    start_response('200 OK',[('Content-Type','text/html')])
    output = """
    <form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="failas" />
    <input type="submit" value="Varom" />
    </form>
    """
    fs = cgi.FieldStorage(fp=environ['wsgi.input'],environ=environ)
    f = fs.getfirst('failas')
    print type(f)
    return output


if __name__ == '__main__' :
    httpd = make_server('',8000,app)
    print 'Serving'
    httpd.serve_forever()
Run Code Online (Sandbox Code Playgroud)

提前致谢!:)

gim*_*mel 7

检查cgi模块描述,有一段讨论如何处理文件上传.

如果字段表示上载的文件,则通过value属性或getvalue()方法访问该值会将内存中的整个文件作为字符串读取.这可能不是你想要的.您可以通过测试filename属性或file属性来测试上载的文件.然后,您可以从文件属性中悠闲地读取数据:

fileitem = form["userfile"]
if fileitem.file:
    # It's an uploaded file; count lines
    linecount = 0
    while 1:
        line = fileitem.file.readline()
        if not line: break
        linecount = linecount + 1
Run Code Online (Sandbox Code Playgroud)

关于你的例子,getfirst()只是一个版本getvalue().尝试更换

f = fs.getfirst('failas')
Run Code Online (Sandbox Code Playgroud)

f = fs['failas'].file
Run Code Online (Sandbox Code Playgroud)

这将返回一个类似文件的对象,可以"闲暇时"阅读.


has*_*zmi 5

最好的方法是不要像gimel建议的那样一次读取文件(甚至每行.

您可以使用一些继承并从FieldStorage扩展一个类,然后覆盖make_file函数.当FieldStorage是文件类型时调用make_file.

供您参考,默认的make_file如下所示:

def make_file(self, binary=None):
    """Overridable: return a readable & writable file.

    The file will be used as follows:
    - data is written to it
    - seek(0)
    - data is read from it

    The 'binary' argument is unused -- the file is always opened
    in binary mode.

    This version opens a temporary file for reading and writing,
    and immediately deletes (unlinks) it.  The trick (on Unix!) is
    that the file can still be used, but it can't be opened by
    another process, and it will automatically be deleted when it
    is closed or when the current process terminates.

    If you want a more permanent file, you derive a class which
    overrides this method.  If you want a visible temporary file
    that is nevertheless automatically deleted when the script
    terminates, try defining a __del__ method in a derived class
    which unlinks the temporary files you have created.

    """
    import tempfile
    return tempfile.TemporaryFile("w+b")
Run Code Online (Sandbox Code Playgroud)

而不是创建临时文件,永久创建文件,无论你想要什么.