Как работает cgi.FieldStorage хранить файлы?
Итак, я играл с raw WSGI, cgi.FieldStorage и загрузка файлов. И я просто не могу понять, как это связано с загрузкой файлов.
сначала казалось, что он просто хранит весь файл в памяти. И я подумал, что это должно быть легко проверить - большой файл должен забивать память!.. Но этого не произошло. Тем не менее, когда я запрашиваю файл, это строка, а не итератор, файловый объект или что-то еще.
Я попытался прочитать источник модуля cgi и нашел некоторые вещи о временных файлах, но он возвращает долбаную строку, а не объект file(-like)! Так... как это работает fscking?!
вот код, который я использовал:
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()
спасибо заранее! :)
3 ответов
проверка описание модуля cgi, есть параграф, в котором обсуждается, как обрабатывать загрузку файлов.
если поле представляет загруженный файл, доступ к значению через атрибут value или
getvalue()
метод читает весь файл в памяти в виде строки. Это может быть не то, чего ты хочешь. Вы можете проверить загруженный файл, проверив атрибут filename или . Тогда вы можете прочитать данные на досуге из атрибута файла:
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
что касается вашего примера, getfirst()
- это просто версия getvalue()
.
попробуйте заменить
f = fs.getfirst('failas')
С
f = fs['failas'].file
это вернет файловый объект, который читается "на досуге".
лучший способ-не читать файл (или даже каждую строку за раз, как предложил гимел).
вы можете использовать некоторое наследование и расширить класс из FieldStorage, а затем переопределить функцию make_file. make_file вызывается, когда FieldStorage имеет тип 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")
вместо того, чтобы создавать temporaryfile, постоянно создавайте файл везде, где хотите.
используя ответ @hasanatkazmi (используется в скрученном приложении), я получил что-то вроде:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# -*- indent: 4 spc -*-
import sys
import cgi
import tempfile
class PredictableStorage(cgi.FieldStorage):
def __init__(self, *args, **kwargs):
self.path = kwargs.pop('path', None)
cgi.FieldStorage.__init__(self, *args, **kwargs)
def make_file(self, binary=None):
if not self.path:
file = tempfile.NamedTemporaryFile("w+b", delete=False)
self.path = file.name
return file
return open(self.path, 'w+b')
имейте в виду, что файл не всегда на cgi модуль. Согласно этим cgi.py
строки он будет создан только в том случае, если содержимое превышает 1000 байт:
if self.__file.tell() + len(line) > 1000:
self.file = self.make_file('')
Итак, вы должны проверить, действительно ли файл был создан с запросом к пользовательскому классу'