遍历FTP列表
我想从一个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
所以我用line[56:]可以得到目录的名字(mysite.com)。我在递归函数里用到了这个。
但是我一直没法让它正常工作。我尝试了很多不同的方法,但都不行。还遇到了很多FTP错误(有时候找不到目录,这个是逻辑问题,有时候服务器返回意外错误,没有日志,我也没法调试)。
总结一下我的问题:如何从FTP服务器获取一个层级目录列表?
5 个回答
2
你可能不喜欢这个答案,但“这要看服务器的情况”或者更准确地说,“这要看服务器的输出格式”。
不同的服务器可以设置成显示不同的输出,所以你最开始的想法在大多数情况下是行不通的。
上面提到的“简单而慢的实现”会导致很多错误,甚至有些FTP服务器会把你踢掉(这可能就是你在大约7次之后遇到的情况...)。
6
这是我写的一个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])
11
这里有一个简单但比较慢的实现方法。之所以慢,是因为它会尝试进入每一个目录来判断它是文件还是文件夹,不过这样做是有效的。你可以通过解析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()