Обход списка FTP - PullRequest
       24

Обход списка FTP

4 голосов
/ 06 декабря 2009

Я пытаюсь получить имя всех каталогов с FTP-сервера и сохранить их в иерархическом порядке в многомерном списке или в формате

Например, сервер со следующей структурой:

/www/
    mysite.com
        images
            png
            jpg

в конце скрипта, даст мне список, такой как

['/www/'
  ['mysite.com'
    ['images'
      ['png'],
      ['jpg']
    ]
  ]
]

Я пытался использовать рекурсивную функцию следующим образом: def traverse (dir): FTP.dir (dir, traverse)

FTP.dir возвращает строки в следующем формате:

drwxr-xr-x    5 leavesc1 leavesc1     4096 Nov 29 20:52 mysite.com

таким образом строка [56:] даст мне только имя каталога (mysite.com). Я использую это в рекурсивной функции.

Но я не могу заставить его работать. Я пробовал много разных подходов и не могу заставить его работать. Также много ошибок FTP (либо не удается найти каталог - что является логической проблемой, а иногда непредвиденные ошибки возвращаются сервером, который не оставляет журнала, и я не могу отладить)

нижний вопрос: Как получить иерархический список каталогов с FTP-сервера?

Ответы [ 5 ]

9 голосов
/ 06 декабря 2009

Вот наивная и медленная реализация. Это медленно, потому что он пытается CWD к каждой записи каталога, чтобы определить, является ли он каталогом или файлом, но это работает. Можно оптимизировать его, анализируя вывод команды LIST, но это сильно зависит от реализации сервера.

import ftplib

def traverse(ftp, depth=0):
    """
    return a recursive listing of an ftp server contents (starting
    from the current directory)

    listing is returned as a recursive dictionary, where each key
    contains a contents of the subdirectory or None if it corresponds
    to a file.

    @param ftp: ftplib.FTP object
    """
    if depth > 10:
        return ['depth > 10']
    level = {}
    for entry in (path for path in ftp.nlst() if path not in ('.', '..')):
        try:
            ftp.cwd(entry)
            level[entry] = traverse(ftp, depth+1)
            ftp.cwd('..')
        except ftplib.error_perm:
            level[entry] = None
    return level

def main():
    ftp = ftplib.FTP("localhost")
    ftp.connect()
    ftp.login()
    ftp.set_pasv(True)

    print traverse(ftp)

if __name__ == '__main__':
    main()
4 голосов
/ 18 февраля 2016

Вот первый черновик скрипта Python 3, который работал для меня. Это намного быстрее, чем звонить cwd(). Передайте в качестве аргументов сервер, порт, каталог, имя пользователя и пароль. Я оставил вывод в виде списка в качестве упражнения для читателя.

import ftplib
import sys

def ftp_walk(ftp, dir):
    dirs = []
    nondirs = []
    for item in ftp.mlsd(dir):
        if item[1]['type'] == 'dir':
            dirs.append(item[0])
        else:
            nondirs.append(item[0])
    if nondirs:
        print()
        print('{}:'.format(dir))
        print('\n'.join(sorted(nondirs)))
    else:
        # print(dir, 'is empty')
        pass
    for subdir in sorted(dirs):
        ftp_walk(ftp, '{}/{}'.format(dir, subdir))

ftp = ftplib.FTP()
ftp.connect(sys.argv[1], int(sys.argv[2]))
ftp.login(sys.argv[4], sys.argv[5])
ftp_walk(ftp, sys.argv[3])
2 голосов
/ 25 июня 2010

Если сервер поддерживает команду MLSD, используйте код «каталог и его потомки» из , который отвечает.

2 голосов
/ 07 декабря 2009

Вам это не понравится, но «это зависит от сервера» или, точнее, «это зависит от формата вывода сервера».

Разные серверы могут быть настроены на отображение разных выходных данных, поэтому ваше первоначальное предложение в общем случае обречено на провал.

Приведенная выше «наивная и медленная реализация» вызовет достаточно ошибок, и некоторые FTP-серверы вас отключат (что, вероятно, произошло после примерно 7 из них ...).

0 голосов
/ 07 декабря 2009

Если мы используем Python, посмотрите на:

http://docs.python.org/library/os.path.html (os.path.walk)

Если для этого уже есть хороший модуль, не изобретайте велосипед. Во всяком случае, не могу поверить, что пост на двух местах выше принес два взлета, наслаждайтесь.

...