2011-07-27 28 views
8

私は生のWSGI、cgi.FieldStorageとファイルのアップロードで遊んできました。そして、私はちょうどそれがファイルアップロードを扱う方法を理解できません。cgi.FieldStorageはどのようにファイルを保存しますか?

最初は、ファイル全体をメモリに保存するように見えました。そして、私はhmをテストするのは簡単なはずだと思いました。大きなファイルがメモリを詰まらせるはずです!それでも、ファイルをリクエストすると、それは文字列であり、イテレータ、ファイルオブジェクト、または何かではありません。

私は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() 

ありがとう:

は、ここで私が使用したコードです! :)

答えて

6

cgi module descriptionを調べると、ファイルのアップロードを処理する方法について説明する段落があります。

フィールドは、value属性または文字列としてメモリ内のファイル全体を読み込みgetvalue()メソッドを介して値にアクセス、アップロードされたファイルを表している場合。これはあなたが望むものではないかもしれません。ファイル名属性またはファイル属性のいずれかをテストして、アップロードされたファイルをテストできます。あなたは、ファイル属性からレジャーでデータを読み取ることができます。

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['failas'].file 

これで

f = fs.getfirst('failas') 

を交換してみてください。

+0

ありがとう:)私は主にDjangoを使用していますが、時にはそれらの低レベルのもので少し遊んでいます。 – Justinas

5

最も良い方法は、ファイル(またはgimelが示唆するように一度に1行ずつ)を読み込まないことです。

継承を使用して、クラスを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は、永久にファイルを作成します。

#!/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モジュールによってを作成されていないことを、警告さ:(ツイストアプリで利用)@hasanatkazmiで解答を使用して

2

は、私のようなものを得ました。コンテンツが1000のバイトを超えた場合にのみ作成されます。これらのcgi.py行によると:

if self.__file.tell() + len(line) > 1000: 
    self.file = self.make_file('') 

だから、あなたは、ファイルが実際にそのようなカスタムクラスのpathフィールドへのクエリを使用して作成されたかどうかを確認する必要があります

if file_field.path: 
    # Using an already created file... 
else: 
    # Creating a temporary named file to store the content. 
    import tempfile 
    with tempfile.NamedTemporaryFile("w+b", delete=False) as f: 
     f.write(file_field.value) 
     # You can save the 'f.name' field for later usage. 

Content-Lengthもめったに思わないフィールドのために設定されている場合は、ファイルには、CGIによって作成されなければなりません。

これだけです。この方法でファイルを予測可能に保存し、アプリのメモリ使用量を削減できます。

関連する問題