6

我正在尝试从 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 服务器获取分层目录列表?

4

5 回答 5

10

这是一个幼稚而缓慢的实现。它很慢,因为它尝试对每个目录条目进行 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()
于 2009-12-06T09:59:56.763 回答
4

这是对我有用的 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])
于 2016-02-18T00:34:17.687 回答
2

您不会喜欢这个,而是“它取决于服务器”,或者更准确地说,“它取决于服务器的输出格式”。

可以设置不同的服务器来显示不同的输出,所以你最初的提议在一般情况下必然会失败。

上面的“幼稚而缓慢的实现”会导致足够多的错误,以至于某些 FTP 服务器会切断您的连接(这可能是其中大约 7 个之后发生的事情......)。

于 2009-12-06T22:01:36.023 回答
2

如果服务器支持该命令,则使用答案中MLSD的“目录及其后代”代码。

于 2010-06-24T23:12:06.050 回答
-3

如果我们使用 Python,请查看:

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

如果已经有一个很好的模块,不要重新发明轮子。不敢相信上面两个位置的帖子有两个上升,无论如何,享受。

于 2009-12-06T22:14:13.203 回答