2011-07-27 8 views
8

तो मैं कच्चे WSGI, cgi.FieldStorage और फ़ाइल अपलोड के साथ खेल रहा हूं। और मैं समझ नहीं पा रहा हूं कि यह फ़ाइल अपलोड से कैसे संबंधित है।cgi.FieldStorage स्टोर फ़ाइलों को कैसे करता है?

पहले ऐसा लगता था कि यह पूरी फाइल को स्मृति में संग्रहीत करता है। और मैंने एचएम सोचा, यह परीक्षण करना आसान होना चाहिए - एक बड़ी फाइल को स्मृति को छिपाना चाहिए! .. और ऐसा नहीं हुआ। फिर भी, जब मैं फ़ाइल का अनुरोध करता हूं, तो यह एक स्ट्रिंग है, न कि इटरेटर, फ़ाइल ऑब्जेक्ट या कुछ भी।

मैं cgi मॉड्यूल के स्रोत को पढ़ने की कोशिश की है और अस्थायी फ़ाइलों के बारे में कुछ बातें मिला, लेकिन यह एक पागल स्ट्रिंग देता है, एक फ़ाइल नहीं (तरह) वस्तु! तो ... यह कैसे काम 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() 

अग्रिम धन्यवाद:

यहाँ कोड मैं का उपयोग किया है है! :)

उत्तर

6

cgi module description का निरीक्षण करने से वहाँ एक पैरा कैसे फ़ाइल अपलोड संभाल करने पर चर्चा है।

एक क्षेत्र एक अपलोड की गई फ़ाइल का प्रतिनिधित्व करता है, तो मूल्य विशेषता या 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 सुझाव) फ़ाइल को पढ़ने के लिए है।

आप कुछ विरासत का उपयोग करें और FieldStorage से एक वर्ग का विस्तार और फिर make_file समारोह ओवरराइड कर सकते हैं। 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") 

बल्कि तो बनाने temporaryfile, स्थायी रूप से फ़ाइल बनाने के भी आप चाहते हैं।

2

@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('') 

तो, आप अगर फ़ाइल वास्तव में एक कस्टम वर्ग 'तो जैसे 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 द्वारा बनाई जानी चाहिए।

यही है। इस तरह आप फ़ाइल को अनुमानित रूप से स्टोर कर सकते हैं, आपके ऐप के मेमोरी उपयोग पदचिह्न को कम कर सकते हैं।