2010-04-04 3 views
4

Мне очень нравится, как я могу легко обмениваться файлами в сети с помощью SimpleHTTPServer, но я бы хотел, чтобы был такой вариант, как «загрузить весь каталог». Есть ли простой (один лайнер) способ реализовать это?Загрузить все каталоги в Python SimpleHTTPServer

Благодаря

ответ

5

Посмотрите на источники, например. онлайн here. Прямо сейчас, если вы вызываете сервер с URL-адресом, который является каталогом, его файл index.html обслуживается, или, что отсутствует, вызывается метод list_directory. Предположительно, вы хотите вместо этого сделать файл zip с содержимым каталога (рекурсивно, я полагаю), и служить этому? Очевидно, что нет способа сделать это с однострочным изменением, так как вы хотите заменить строки 68-80 (в методе send_head) плюс весь метод list_directory, строки 98-137 - это уже хотя бы изменение более 50 строк ;-).

Если у вас все в порядке с несколькими дюжинами строк, а не семантикой, которую я описал, вы можете, конечно, построить требуемый zipfile как объект cStringIO.StringIO с классом ZipFile и заполнить его os.walk в рассматриваемой директории (предполагая, что вы хотите, рекурсивно, также получить все подкаталоги). Но это определенно не будет однострочным ;-).

4

Там не один лайнер, который будет делать это, а также то, что вы подразумеваете под «скачать весь реж», как деготь или почтовый индекс?

В любом случае вы можете выполнить следующие шаги

  1. Выведите класс от SimpleHTTPRequestHandler или может быть просто скопировать его код
  2. метод Изменить list_directory вернуть ссылку на «загрузить всю папку»
  3. Изменить метод CopyFile так что для ваших ссылок вы застегиваете весь каталог и возвращаете его
  4. Вы можете кэшировать zip, чтобы вы не застегивали папку каждый раз, вместо этого видите, что какой-либо файл изменен или нет.

Было бы весело провести время :)

+0

Если вы не изменили 'send_head', вы не собираетесь копировать каталоги, содержащие' index.html', поэтому изменение немного более распространено, чем тот, который вы описали (я дал детали и номера строк для текущей онлайн-версии источников в моем ответе, которые пересекли вас на проводе на несколько секунд). –

3

я что модификация для вас, я не знаю, если there'are лучшие способы сделать это, но:

Просто сохраните файл (Ex .: 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() 
Смежные вопросы