如何在Python中通过SFTP连接后列出目录中的所有文件夹和文件

Posted

技术标签:

【中文标题】如何在Python中通过SFTP连接后列出目录中的所有文件夹和文件【英文标题】:How to list all the folders and files in the directory after connecting through SFTP in Python 【发布时间】:2012-08-31 00:08:38 【问题描述】:

我正在使用 Python 并尝试连接到 SFTP,并希望从那里检索 XML 文件,并且需要将其放置在我的本地系统中。下面是代码:

import paramiko

sftpURL   =  'sftp.somewebsite.com'
sftpUser  =  'user_name'
sftpPass  =  'password'

ssh = paramiko.SSHClient()
# automatically add keys without requiring human intervention
ssh.set_missing_host_key_policy( paramiko.AutoAddPolicy() )

ssh.connect(sftpURL, username=sftpUser, password=sftpPass)

ftp = ssh.open_sftp()
files = ftp.listdir()
print files

这里连接成功。现在我想查看所有文件夹和所有文件,并且需要进入所需的文件夹以从那里检索 XML 文件。

最后我的意图是在连接到 SFTP 服务器后查看所有文件夹和文件。

在上面的代码中,我使用了ftp.listdir(),通过它我得到了如下所示的输出

['.bash_logout', '.bash_profile', '.bashrc', '.mozilla', 'testfile_248.xml']

我想知道是否只有这些文件存在?

我上面使用的命令也可以查看文件夹吗?

查看所有文件夹和文件的命令是什么?

【问题讨论】:

【参考方案1】:

SFTPClient.listdir 返回所有内容、文件和文件夹。

是否有文件夹,要从文件中区分它们,请改用SFTPClient.listdir_attr。它返回SFTPAttributes 的集合。

from stat import S_ISDIR, S_ISREG
for entry in sftp.listdir_attr(remotedir):
    mode = entry.st_mode
    if S_ISDIR(mode):
        print(entry.filename + " is folder")
    elif S_ISREG(mode):
        print(entry.filename + " is file")

@Oz123 接受的答案效率低下。 SFTPClient.listdir 内部调用 SFTPClient.listdir_attr 并丢弃大部分信息,仅返回文件和文件夹名称。然后,答案会通过为每个文件调用 SFTPClient.lstat 来无用且费力地重新检索所有数据。

另见How to fetch sizes of all SFTP files in a directory through Paramiko。


强制警告:不要使用AutoAddPolicy - 这样做会失去对MITM attacks 的保护。有关正确的解决方案,请参阅Paramiko "Unknown Server"。

【讨论】:

【参考方案2】:

一种快速的解决方案是检查ftp.listdir() 中每个对象的lstat 的输出。

这是列出所有目录的方法。

>>> for i in ftp.listdir():
...     lstatout=str(ftp.lstat(i)).split()[0]
...     if 'd' in lstatout: print i, 'is a directory'
... 

文件是相反的搜索:

>>> for i in ftp.listdir():
...     lstatout=str(ftp.lstat(i)).split()[0]
...     if 'd' not in lstatout: print i, 'is a file'
... 

【讨论】:

依赖SFTPAttributes 的字符串化行为是一种可怕的、可怕的黑客行为。为什么不正确地使用stat.S_ISDIR(lstatout.st_mode) @PANDAStack - ftp.lstat(i) 返回类 SFTPAttributes 的一个实例。这个答案的方式取决于库如何选择具有SFTPAttributes look__repr__,这是一个完全程序员调试而设计的界面,并且可能没有经过测试或保证不变,即使在补丁版本号之间也是如此。 基本上,这样做相当于从控制台解析调试输出。它可能会起作用,但它非常脆弱,只有在绝对必要的情况下才应该这样做,并且没有其他选择。在这种情况下,SFTPAttributes 类的全部意义在于方便地封装有关远程主机上路径的元数据,因此不只是按照它假定的工作方式使用它,坦率地说是愚蠢的。跨度> @PANDAStack - st_mode 由 POSIX 定义。看看stat() man pages。另外,this question on SE. 这是代码效率低下。请参阅my answer 以获得正确的解决方案。【参考方案3】:

这是我想出的解决方案。基于https://***.com/a/59109706。我的解决方案给出了一个漂亮的输出。

更新我稍作修改以纳入 Martin 的建议。现在,与使用 isdirlistdir 的初始版本相比,我的代码速度相当快

# prefix components:
space =  '    '
branch = '│   '
# pointers:
tee =    '├── '
last =   '└── '

def stringpath(path):
    # just a helper to get string of PosixPath
    return str(path)

from pathlib import Path
from stat import S_ISDIR
def tree_sftp(sftp, path='.', parent='/', prefix=''):
    """
    Loop through files to print it out
    for file in tree_sftp(sftp):
        print(file)
    """
    fullpath = Path(parent, path)
    strpath = stringpath(fullpath)

    dirs = sftp.listdir_attr(strpath)
    pointers = [tee] * (len(dirs) - 1) + [last]
    pdirs = [Path(fullpath, d.filename) for d in dirs]
    sdirs = [stringpath(path) for path in pdirs]

    for pointer, sd, d in zip(pointers, sdirs, dirs):
        yield prefix + pointer + d.filename
        if S_ISDIR(d.st_mode):
            extension = branch if pointer == tee else space
            yield from tree_sftp(sftp, sd, prefix=prefix + extension)

你可以像这样使用pysftp来试试

import pysftp
with pysftp.Connection(HOSTNAME, USERNAME, PASSWORD) as sftp:
    for file in tree_sftp(sftp):
        print(file)

如果适合你,请告诉我。

【讨论】:

第三件事是你不应该在 SFTP 路径上使用 Python Path 类。 Path 使用可能与 SFTP 约定不匹配的本地文件系统约定。特别是在 Windows 上,您的代码可能会失败。 python Path 仅用于简单的路径连接。我将其转换为字符串以与 pysftp 一起使用。我没有包含stringpath 函数,我只是注意到了。让我补充一下。它只是一个帮手。 就是这样,SFTP 总是使用正斜杠。而Path 将使用本地系统路径分隔符。如果这不是正斜杠(如在 Windows 上),您的代码将失败。您正在引入与 psftp 的 get_rput_r 相同的问题。见Python pysftp put_r does not work on Windows。您可能想明确使用PosixPath

以上是关于如何在Python中通过SFTP连接后列出目录中的所有文件夹和文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中通过 SFTP 检查 S_ISREG 以获取 Windows NTFS 文件?

如何在 Cyber​​Duck 中通过 SFTP 使用 sudo?

如何在java中通过SFTP传输文件? [复制]

用于从该框中通过 SSH 连接到 jumphost 和 sftp 的 Python 脚本

如何在 R 中使用 DBI 连接到 bigquery 数据库后列出表的字段

jsch连接sftp后连接未释放掉问题排查