来自 Linux 的 Python pysftp get_r 在 Linux 上运行良好,但在 Windows 上不起作用

来自 Linux 的 Python pysftp get_r 在 Linux 上运行良好,但在 Windows 上不起作用

问题描述:

我想使用 Python 2.7 使用 SFTP 递归地将包含文件和子文件夹的整个目录结构从 Linux 服务器复制到本地计算机(Windows 和 Linux).

I would like to copy an entire directory structure with files and subfolders recursively using SFTP from a Linux server to a local machine (both Windows and Linux) using Python 2.7.

我可以在同一台机器上使用 WinSCP ping 服务器并下载文件.

I am able to ping the server and download the files using WinSCP from the same machine.

我尝试了以下代码,在 Linux 上运行良好,但在 Windows 上不起作用.

I tried the following code, works fine on Linux but not on Windows.

我试过/os.join,都给我同样的错误,也检查了权限.

I tried , /, os.join, all gives me same error, checked permissions as well.

import os
import pysftp

cnopts = pysftp.CnOpts()
cnopts.hostkeys = None    # disable host key checking.
sftp=pysftp.Connection('xxxx.xxx.com', username='xxx', password='xxx', cnopts=cnopts)
sftp.get_r('/abc/def/ghi/klm/mno', 'C:pqr', preserve_mtime=False)

File "<stdin>", line 1, in <module> File "C:Python27libsite-packagespysftp_init_.py", line 311, in get_r preserve_mtime=preserve_mtime)
File "C:Python27libsite-packagespysftp_init_.py", line 249, in get self._sftp.get(remotepath, localpath, callback=callback)
File "C:Python27libsite-packagesparamikosftp_client.py", line 769, in get with open(localpath, 'wb') as fl: IOError: [Errno 2] No such file or directory: u'C:\pqr\./abc/def/ghi/klm/mno/.nfs0000000615c569f500000004' 

确实,pysftp get_r 在 Windows 上不起作用.它对远程 SFTP 路径使用 os.sepos.path 函数,这是怎么回事,因为 SFTP 路径总是使用正斜杠.

Indeed, pysftp get_r does not work on Windows. It uses os.sep and os.path functions for remote SFTP paths, what is wrong, as SFTP paths always use a forward slash.

但您可以轻松实现便携式替换.

But you can easily implement a portable replacement.

import os
from stat import S_ISDIR, S_ISREG

def get_r_portable(sftp, remotedir, localdir, preserve_mtime=False):
    for entry in sftp.listdir_attr(remotedir):
        remotepath = remotedir + "/" + entry.filename
        localpath = os.path.join(localdir, entry.filename)
        mode = entry.st_mode
        if S_ISDIR(mode):
            try:
                os.mkdir(localpath)
            except OSError:     
                pass
            get_r_portable(sftp, remotepath, localpath, preserve_mtime)
        elif S_ISREG(mode):
            sftp.get(remotepath, localpath, preserve_mtime=preserve_mtime)

像这样使用:

get_r_portable(sftp, '/abc/def/ghi/klm/mno', 'C:\pqr', preserve_mtime=False) 


请注意,如果您不想使用 pysftp,可以轻松修改上述代码以直接与 Paramiko 一起使用.Paramiko SFTPClient 也有 listdir_attrget 方法.唯一的区别是 Paramiko 的 get 没有 preserve_mtime 参数/功能(但可以轻松实现,如果需要的话).


Note that the above code can be easily modified to work with Paramiko directly, in case you do not want to use pysftp. The Paramiko SFTPClient class also has the listdir_attr and get methods. The only difference is that the Paramiko's get does not have the preserve_mtime parameter/functionality (but it can be implemented easily, if you need it).

可能的代码修改:

有关 put_r 的类似问题,请参阅:
Python pysftp put_r 在 Windows 上不起作用

For a similar question about put_r, see:
Python pysftp put_r does not work on Windows

旁注:不要禁用主机密钥检查".您正在失去对MITM 攻击的保护.

Side note: Do not "disable host key checking". You are losing a protection against MITM attacks.

有关正确的解决方案,请参阅使用 pysftp 验证主机密钥.

For a correct solution, see Verify host key with pysftp.