Если это просто проблема, которую вы хотите решить, я могу предложить команду wget
:
cd c:\destination
wget --mirror --continue --no-host-directories --user=username --password=s3cr3t ftp://hostname/source/path/
Опция --continue
может быть очень опасной, если файлы изменяют на сервере. Если файлы добавляются только , это очень удобно.
Однако, если это учебное упражнение для вас, и вы хотите, чтобы ваша программа работала, я думаю, вам следует начать с рассмотрения этой строки:
for subdir, dirs, files in os.walk(directory):
directory
был исходным каталогом remote в большинстве ваших программ, но функция os.walk()
не может пройти каталог remote . Вам нужно перебирать возвращаемые файлы самостоятельно, используя обратный вызов, предоставленный функции retrlines
.
Взгляните на опции MLSD
или NLST
вместо LIST
, их, вероятно, будет легче разобрать. (Обратите внимание, что FTP на самом деле не определяет, как должны выглядеть списки; он всегда предназначался для управления человеком за консолью или передачи конкретного имени файла. Поэтому программы, которые делают умные вещи с помощью списков FTP, например, представляют их GUI, вероятно, должен иметь огромные кучи кода особого случая для нечетных или непонятных серверов. И они, вероятно, все делают что-то глупое, когда сталкиваются с вредоносными именами файлов.
Можете ли вы использовать sftp
вместо этого? sftp
имеет спецификацию того, как списки файлов должны быть проанализированы, не передает имя пользователя / пароль в открытом виде и не имеет гигантского раздражения пассивных и активных соединений - это просто использует одно соединение, что означает, что оно работает через большее количество межсетевых экранов, чем FTP.
Редактировать : Вам необходимо передать вызываемый объект в функцию retrlines
. Вызываемый объект - это либо экземпляр класса, который определил метод __call__
, либо функция. Хотя эту функцию проще описать, экземпляр класса может быть более полезным. (Вы можете использовать экземпляр для сбора имен файлов, но функция должна будет записывать в глобальную переменную. Плохо.)
Вот один из самых простых вызываемых объектов:
>>> class c:
... def __call__(self, *args):
... print(args)
...
>>> f = c()
>>> f('hello')
('hello',)
>>> f('hello', 'world')
('hello', 'world')
Это создает новый класс c
, который определяет метод экземпляра __call__
. Это просто печатает свои аргументы довольно глупо, но показывает, насколько мы минимальны. :)
Если вы хотите что-то умнее, оно может сделать что-то вроде этого:
class handle_lines:
def __init__(self):
self.lines = []
def __call__(self, *args):
self.lines << args[0]
Вызовите iterlines
с объектом этого класса, затем посмотрите в lines
члене объекта для получения подробной информации.