2010-04-04 72 views

回答

5

看看來源,例如在線here。現在,如果您使用作爲目錄的URL調用服務器,則會提供其index.html文件,或者缺少該文件,將調用list_directory方法。據推測,你想要做一個zip文件與目錄的內容(遞歸,我想象),併爲此?很明顯,沒有辦法通過單行更改來完成它,因爲您想要替換現在的第68-80行(方法send_head)以及整個方法list_directory第98-137行 - 這已經至少是一個變化超過50行;-)。

如果你可以改變幾十行而不是一行,並且我描述的語義是你想要的,你當然可以使用ZipFile類來建立所需的zipfile作爲cStringIO.StringIO對象,並且在目錄中填充os.walk(假設您想遞歸獲取所有子目錄)。但絕對不會是單線的;-)。

4

沒有一個班輪這將做到這一點,還你是什麼意思的「下載整個目錄」焦油或zip?

反正你可以按照以下步驟

  1. 從SimpleHTTPRequestHandler派生類,或者可能只是複製其代碼
  2. 變化list_directory方法返回一個鏈接到「下載整個文件夾」
  3. 變化的CopyFile方法這樣你的鏈接就可以用zip壓縮整個目錄並返回它
  4. 你可以緩存壓縮文件,這樣你就不會每次壓縮文件夾,而是看看是否有文件被修改

將是一個有趣的練習:)

+0

除非你也改變'send_head',否則你不會壓縮包含'index.html'的目錄,所以這個改變比你描述的更普遍(我給了我的答案中當前在線版源代碼的詳細信息和行號,這會在幾秒鐘內將您的信息傳遞給您)。 – 2010-04-04 05:43:42

3

我爲你修改,我不知道是否there'are更好的方法來做到這一點,但:

只是保存文件(例:ThreadedHTTPServer.py)和訪問爲:

$ python -m /path/to/ThreadedHTTPServer PORT

BPaste Raw Version

的修改也適用於螺紋的方式,所以你不會有下載和導航的同時問題,代碼沒有組織,但:

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler 
from SocketServer import ThreadingMixIn 
import threading 
import SimpleHTTPServer 
import sys, os, zipfile 

PORT = int(sys.argv[1]) 

def send_head(self): 
    """Common code for GET and HEAD commands. 

    This sends the response code and MIME headers. 

    Return value is either a file object (which has to be copied 
    to the outputfile by the caller unless the command was HEAD, 
    and must be closed by the caller under all circumstances), or 
    None, in which case the caller has nothing further to do. 

    """ 
    path = self.translate_path(self.path) 
    f = None 

    if self.path.endswith('?download'): 

     tmp_file = "tmp.zip" 
     self.path = self.path.replace("?download","") 

     zip = zipfile.ZipFile(tmp_file, 'w') 
     for root, dirs, files in os.walk(path): 
      for file in files: 
       if os.path.join(root, file) != os.path.join(root, tmp_file): 
        zip.write(os.path.join(root, file)) 
     zip.close() 
     path = self.translate_path(tmp_file) 

    elif os.path.isdir(path): 

     if not self.path.endswith('/'): 
      # redirect browser - doing basically what apache does 
      self.send_response(301) 
      self.send_header("Location", self.path + "/") 
      self.end_headers() 
      return None 
     else: 

      for index in "index.html", "index.htm": 
       index = os.path.join(path, index) 
       if os.path.exists(index): 
        path = index 
        break 
      else: 
       return self.list_directory(path) 
    ctype = self.guess_type(path) 
    try: 
     # Always read in binary mode. Opening files in text mode may cause 
     # newline translations, making the actual size of the content 
     # transmitted *less* than the content-length! 
     f = open(path, 'rb') 
    except IOError: 
     self.send_error(404, "File not found") 
     return None 
    self.send_response(200) 
    self.send_header("Content-type", ctype) 
    fs = os.fstat(f.fileno()) 
    self.send_header("Content-Length", str(fs[6])) 
    self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) 
    self.end_headers() 
    return f 

def list_directory(self, path): 

    try: 
     from cStringIO import StringIO 
    except ImportError: 
     from StringIO import StringIO 
    import cgi, urllib 

    """Helper to produce a directory listing (absent index.html). 

    Return value is either a file object, or None (indicating an 
    error). In either case, the headers are sent, making the 
    interface the same as for send_head(). 

    """ 
    try: 
     list = os.listdir(path) 
    except os.error: 
     self.send_error(404, "No permission to list directory") 
     return None 
    list.sort(key=lambda a: a.lower()) 
    f = StringIO() 
    displaypath = cgi.escape(urllib.unquote(self.path)) 
    f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">') 
    f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath) 
    f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath) 
    f.write("<a href='%s'>%s</a>\n" % (self.path+"?download",'Download Directory Tree as Zip')) 
    f.write("<hr>\n<ul>\n") 
    for name in list: 
     fullname = os.path.join(path, name) 
     displayname = linkname = name 
     # Append/for directories or @ for symbolic links 
     if os.path.isdir(fullname): 
      displayname = name + "/" 
      linkname = name + "/" 
     if os.path.islink(fullname): 
      displayname = name + "@" 
      # Note: a link to a directory displays with @ and links with/
     f.write('<li><a href="%s">%s</a>\n' 
       % (urllib.quote(linkname), cgi.escape(displayname))) 
    f.write("</ul>\n<hr>\n</body>\n</html>\n") 
    length = f.tell() 
    f.seek(0) 
    self.send_response(200) 
    encoding = sys.getfilesystemencoding() 
    self.send_header("Content-type", "text/html; charset=%s" % encoding) 
    self.send_header("Content-Length", str(length)) 
    self.end_headers() 
    return f 

Handler = SimpleHTTPServer.SimpleHTTPRequestHandler 
Handler.send_head = send_head 
Handler.list_directory = list_directory 

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    """Handle requests in a separate thread.""" 

if __name__ == '__main__': 
    server = ThreadedHTTPServer(('0.0.0.0', PORT), Handler) 
    print 'Starting server, use <Ctrl-C> to stop' 
    server.serve_forever() 
相關問題