Python FTP下载目录中的所有文件

Python FTP下载目录中的所有文件,python,ftp,ftplib,Python,Ftp,Ftplib,我正在编写一个脚本,通过FTP从一个目录下载所有文件。到目前为止,我已成功连接并获取了一个文件,但我似乎无法成批工作(从目录中获取所有文件)。到目前为止,我所拥有的是: from ftplib import FTP import os, sys, os.path def handleDownload(block): file.write(block) print ".", ddir='C:\\Data\\test\\' os.chdir(ddir) ftp = FTP('te

我正在编写一个脚本,通过FTP从一个目录下载所有文件。到目前为止,我已成功连接并获取了一个文件,但我似乎无法成批工作(从目录中获取所有文件)。到目前为止,我所拥有的是:

from ftplib import FTP
import os, sys, os.path

def handleDownload(block):
    file.write(block)
    print ".",

ddir='C:\\Data\\test\\'
os.chdir(ddir)
ftp = FTP('test1/server/')

print 'Logging in.'
ftp.login('user1\\anon', 'pswrd20')
directory = '\\data\\test\\'

print 'Changing to ' + directory
ftp.cwd(directory)
ftp.retrlines('LIST')

print 'Accessing files'

for subdir, dirs, files in os.walk(directory):
    for file in files: 
        full_fname = os.path.join(root, fname);  
        print 'Opening local file ' 
        ftp.retrbinary('RETR C:\\Data\\test\\' + fname,
                       handleDownload,
                       open(full_fname, 'wb'));
        print 'Closing file ' + filename
        file.close();
ftp.close()

我敢打赌,当我运行它时,您可以看出它没有多大作用,因此任何改进建议都将不胜感激。

如果这只是您想解决的问题,我可能建议使用
wget
命令:

cd c:\destination
wget --mirror --continue --no-host-directories --user=username --password=s3cr3t ftp://hostname/source/path/
如果服务器上的文件发生更改,
--continue
选项可能非常危险。如果只添加文件,那么它是非常友好的

但是,如果这是一个学习练习,并且您想让您的程序正常运行,我认为您应该从以下几行开始:

directory
在大多数程序中都是远程源目录,但是
os.walk()
函数无法遍历远程目录。您需要自己使用提供给函数的回调来迭代返回的文件

查看
MLSD
NLST
选项,而不是
LIST
,它们可能更容易解析。(请注意,FTP实际上并没有指定列表的外观;它总是由控制台上的人来驱动,或者传输特定的文件名。因此,使用FTP列表进行巧妙操作的程序,例如在GUI中向用户显示这些列表,可能必须有大量的特殊情况代码,用于奇怪或晦涩的服务器。它们可能会(当遇到恶意文件名时,所有人都会做一些愚蠢的事情。)

你能改用吗
sftp
确实有一个文件列表解析的规范,没有明文传输用户名/密码,也没有被动连接和主动连接的巨大麻烦——它只是使用单一连接,这意味着它比FTP可以跨更多防火墙工作

Edit:您需要将一个“可调用”对象传递给
retrlines
函数。可调用对象可以是定义了
\uuuu call\uuu
方法的类的实例,也可以是函数。虽然函数可能更容易描述,但类的实例可能更有用。(可以使用实例收集文件名,但函数必须写入全局变量。错误。)

下面是一个最简单的可调用对象:

>>> class c:
...  def __call__(self, *args):
...   print(args)
...
>>> f = c()
>>> f('hello')
('hello',)
>>> f('hello', 'world')
('hello', 'world')
这将创建一个新类
c
,该类定义了一个实例方法
\uuuuu调用\uuuuu
。这只是以一种相当愚蠢的方式打印了它的论点,但它显示了我们所谈论的是多么微不足道。:)

如果你想要更聪明的东西,它可以做如下事情:

class handle_lines:
  def __init__(self):
    self.lines = []
  def __call__(self, *args):
    self.lines << args[0]
类句柄\u行:
定义初始化(自):
self.lines=[]
定义调用(self,*args):

self.lines如果这只是您想要解决的问题,我建议使用
wget
命令:

cd c:\destination
wget --mirror --continue --no-host-directories --user=username --password=s3cr3t ftp://hostname/source/path/
如果服务器上的文件发生更改,
--continue
选项可能非常危险。如果只添加文件,那么它是非常友好的

但是,如果这是一个学习练习,并且您想让您的程序正常运行,我认为您应该从以下几行开始:

directory
在大多数程序中都是远程源目录,但是
os.walk()
函数无法遍历远程目录。您需要自己使用提供给函数的回调来迭代返回的文件

查看
MLSD
NLST
选项,而不是
LIST
,它们可能更容易解析。(请注意,FTP实际上并没有指定列表的外观;它总是由控制台上的人来驱动,或者传输特定的文件名。因此,使用FTP列表进行巧妙操作的程序,例如在GUI中向用户显示这些列表,可能必须有大量的特殊情况代码,用于奇怪或晦涩的服务器。它们可能会(当遇到恶意文件名时,所有人都会做一些愚蠢的事情。)

你能改用吗
sftp
确实有一个文件列表解析的规范,没有明文传输用户名/密码,也没有被动连接和主动连接的巨大麻烦——它只是使用单一连接,这意味着它比FTP可以跨更多防火墙工作

Edit:您需要将一个“可调用”对象传递给
retrlines
函数。可调用对象可以是定义了
\uuuu call\uuu
方法的类的实例,也可以是函数。虽然函数可能更容易描述,但类的实例可能更有用。(可以使用实例收集文件名,但函数必须写入全局变量。错误。)

下面是一个最简单的可调用对象:

>>> class c:
...  def __call__(self, *args):
...   print(args)
...
>>> f = c()
>>> f('hello')
('hello',)
>>> f('hello', 'world')
('hello', 'world')
这将创建一个新类
c
,该类定义了一个实例方法
\uuuuu调用\uuuuu
。这只是以一种相当愚蠢的方式打印了它的论点,但它显示了我们所谈论的是多么微不足道。:)

如果你想要更聪明的东西,它可以做如下事情:

class handle_lines:
  def __init__(self):
    self.lines = []
  def __call__(self, *args):
    self.lines << args[0]
类句柄\u行:
定义初始化(自):
self.lines=[]
定义调用(self,*args):

self.lines我已经设法破解了这个问题,现在为未来的访问者发布了相关的代码:

filenames = ftp.nlst() # get filenames within the directory
print filenames

for filename in filenames:
    local_filename = os.path.join('C:\\test\\', filename)
    file = open(local_filename, 'wb')
    ftp.retrbinary('RETR '+ filename, file.write)

    file.close()

ftp.quit() # This is the “polite” way to close a connection

这对我在Python 2.5和Windows XP上起到了作用。

我已经设法破解了这个问题,因此现在为未来的访问者发布了相关的代码:

filenames = ftp.nlst() # get filenames within the directory
print filenames

for filename in filenames:
    local_filename = os.path.join('C:\\test\\', filename)
    file = open(local_filename, 'wb')
    ftp.retrbinary('RETR '+ filename, file.write)

    file.close()

ftp.quit() # This is the “polite” way to close a connection

这对我在Python2.5、Windows XP上很有效。

我们可以从Python程序调用dos脚本,而不是使用Python lib通过ftp下载目录。在dos脚本中,我们将使用本机ftp协议,该协议可以使用
mget*.
从文件夹下载所有文件

fetch.bat
ftp -s:fetch.txt

fetch.txt
open <ipaddress>
<userid>
<password>
bin (set the mnode to binary)
cd </desired directory>
mget *.*
bye

fetch.py
import os
os.system("fetch.bat")
fetch.bat
ftp-s:fetch.txt
fetch.txt
打开
bin(将mnode设置为二进制)
光盘
mget**
再见
获取.py
导入操作系统
操作系统(“fetch.bat”)

而不是使用Python库进行ftp