使用 Paramiko 进行目录传输

发布于 2024-10-06 21:16:28 字数 165 浏览 3 评论 0原文

如何使用Paramiko传输完整的目录? 我正在尝试使用:

sftp.put("/Folder1","/Folder2")

这给了我这个错误 -

错误:[Errno 21] 是一个目录

How do you use Paramiko to transfer complete directories?
I'm trying to use:

sftp.put("/Folder1","/Folder2")

which is giving me this error -

Error : [Errno 21] Is a directory

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

你又不是我 2024-10-13 21:16:28

您可以子类化 paramiko.SFTPClient 并向其添加以下方法:

import paramiko
import os

class MySFTPClient(paramiko.SFTPClient):
    def put_dir(self, source, target):
        ''' Uploads the contents of the source directory to the target path. The
            target directory needs to exists. All subdirectories in source are 
            created under target.
        '''
        for item in os.listdir(source):
            if os.path.isfile(os.path.join(source, item)):
                self.put(os.path.join(source, item), '%s/%s' % (target, item))
            else:
                self.mkdir('%s/%s' % (target, item), ignore_existing=True)
                self.put_dir(os.path.join(source, item), '%s/%s' % (target, item))

    def mkdir(self, path, mode=511, ignore_existing=False):
        ''' Augments mkdir by adding an option to not fail if the folder exists  '''
        try:
            super(MySFTPClient, self).mkdir(path, mode)
        except IOError:
            if ignore_existing:
                pass
            else:
                raise

要使用它:

transport = paramiko.Transport((HOST, PORT))
transport.connect(username=USERNAME, password=PASSWORD)
sftp = MySFTPClient.from_transport(transport)
sftp.mkdir(target_path, ignore_existing=True)
sftp.put_dir(source_path, target_path)
sftp.close()

You can subclass paramiko.SFTPClient and add the following method to it:

import paramiko
import os

class MySFTPClient(paramiko.SFTPClient):
    def put_dir(self, source, target):
        ''' Uploads the contents of the source directory to the target path. The
            target directory needs to exists. All subdirectories in source are 
            created under target.
        '''
        for item in os.listdir(source):
            if os.path.isfile(os.path.join(source, item)):
                self.put(os.path.join(source, item), '%s/%s' % (target, item))
            else:
                self.mkdir('%s/%s' % (target, item), ignore_existing=True)
                self.put_dir(os.path.join(source, item), '%s/%s' % (target, item))

    def mkdir(self, path, mode=511, ignore_existing=False):
        ''' Augments mkdir by adding an option to not fail if the folder exists  '''
        try:
            super(MySFTPClient, self).mkdir(path, mode)
        except IOError:
            if ignore_existing:
                pass
            else:
                raise

To use it:

transport = paramiko.Transport((HOST, PORT))
transport.connect(username=USERNAME, password=PASSWORD)
sftp = MySFTPClient.from_transport(transport)
sftp.mkdir(target_path, ignore_existing=True)
sftp.put_dir(source_path, target_path)
sftp.close()
你穿错了嫁妆 2024-10-13 21:16:28

您需要像在本地使用 python 一样执行此操作(如果您没有使用 Shutils)。

os.walk()sftp.mkdir()sftp.put() 结合起来。您可能还需要使用 os.path.islink() 检查每个文件和目录,具体取决于您是否要解析符号链接。

You'll need to do this just like you would locally with python (if you weren't using shutils).

Combine os.walk(), with sftp.mkdir() and sftp.put(). You may also want to check each file and directory with os.path.islink() depending on whether you want to resolve symlinks or not.

迷离° 2024-10-13 21:16:28

这是我的代码:

import errno
import os
import stat

def download_files(sftp_client, remote_dir, local_dir):
    if not exists_remote(sftp_client, remote_dir):
        return

    if not os.path.exists(local_dir):
        os.mkdir(local_dir)

    for filename in sftp_client.listdir(remote_dir):
        if stat.S_ISDIR(sftp_client.stat(remote_dir + filename).st_mode):
            # uses '/' path delimiter for remote server
            download_files(sftp_client, remote_dir + filename + '/', os.path.join(local_dir, filename))
        else:
            if not os.path.isfile(os.path.join(local_dir, filename)):
                sftp_client.get(remote_dir + filename, os.path.join(local_dir, filename))


def exists_remote(sftp_client, path):
    try:
        sftp_client.stat(path)
    except IOError, e:
        if e.errno == errno.ENOENT:
            return False
        raise
    else:
        return True

Here's my piece of code:

import errno
import os
import stat

def download_files(sftp_client, remote_dir, local_dir):
    if not exists_remote(sftp_client, remote_dir):
        return

    if not os.path.exists(local_dir):
        os.mkdir(local_dir)

    for filename in sftp_client.listdir(remote_dir):
        if stat.S_ISDIR(sftp_client.stat(remote_dir + filename).st_mode):
            # uses '/' path delimiter for remote server
            download_files(sftp_client, remote_dir + filename + '/', os.path.join(local_dir, filename))
        else:
            if not os.path.isfile(os.path.join(local_dir, filename)):
                sftp_client.get(remote_dir + filename, os.path.join(local_dir, filename))


def exists_remote(sftp_client, path):
    try:
        sftp_client.stat(path)
    except IOError, e:
        if e.errno == errno.ENOENT:
            return False
        raise
    else:
        return True
安人多梦 2024-10-13 21:16:28

只需使用 paramiko 即可轻松完成这一切。

以下代码的高级摘要是:

- 连接到 SFTP(步骤 1 到 3)

- 指定您的源文件夹和目标文件夹。 (步骤 4)

- 将它们一一复制到您喜欢的任何地方(我已将它们发送到/tmp/)。 (步骤5)

import paramiko

# 1 - Open a transport
host="your-host-name"
port = port_number
transport = paramiko.Transport((host, port))

# 2 - Auth
password="sftp_password"
username="sftp_username"
transport.connect(username = username, password = password)

# 3 - Go!

sftp = paramiko.SFTPClient.from_transport(transport)

# 4 - Specify your source and target folders.
source_folder="some/folder/path/on/sftp"
inbound_files=sftp.listdir(source_folder)

# 5 - Download all files from that path
for file in inbound_files :
    filepath = source_folder+file
    localpath = "/tmp/"+file
    sftp.get(filepath, localpath)

This can all be done quite easily using just paramiko.

A high level summary of the code below is:

- connect to the SFTP (steps 1 to 3)

- specify your source and target folders. (step 4)

- copy them over one by one to wherever you like (I've sent them to /tmp/). (step 5)

import paramiko

# 1 - Open a transport
host="your-host-name"
port = port_number
transport = paramiko.Transport((host, port))

# 2 - Auth
password="sftp_password"
username="sftp_username"
transport.connect(username = username, password = password)

# 3 - Go!

sftp = paramiko.SFTPClient.from_transport(transport)

# 4 - Specify your source and target folders.
source_folder="some/folder/path/on/sftp"
inbound_files=sftp.listdir(source_folder)

# 5 - Download all files from that path
for file in inbound_files :
    filepath = source_folder+file
    localpath = "/tmp/"+file
    sftp.get(filepath, localpath)
风筝在阴天搁浅。 2024-10-13 21:16:28

适合我做这样的事情,所有文件夹和文件都复制到远程服务器。

parent = os.path.expanduser("~")
for dirpath, dirnames, filenames in os.walk(parent):
    remote_path = os.path.join(remote_location, dirpath[len(parent)+1:])
        try:
            ftp.listdir(remote_path)
        except IOError:
            ftp.mkdir(remote_path)

        for filename in filenames:
            ftp.put(os.path.join(dirpath, filename), os.path.join(remote_path, filename))

Works for me doing something like this, all folder and files are copied to the remote server.

parent = os.path.expanduser("~")
for dirpath, dirnames, filenames in os.walk(parent):
    remote_path = os.path.join(remote_location, dirpath[len(parent)+1:])
        try:
            ftp.listdir(remote_path)
        except IOError:
            ftp.mkdir(remote_path)

        for filename in filenames:
            ftp.put(os.path.join(dirpath, filename), os.path.join(remote_path, filename))
め七分饶幸 2024-10-13 21:16:28

您可以将 sftp = self.client.open_sftp() 替换为 paramiko 的,并在此处删除 libcloud

import os.path
from stat import S_ISDIR
from libcloud.compute.ssh import SSHClient
from paramiko.sftp import SFTPError

class CloudSSHClient(SSHClient):


    @staticmethod
    def normalize_dirpath(dirpath):
        while dirpath.endswith("/"):
            dirpath = dirpath[:-1]
        return dirpath


    def mkdir(self, sftp, remotepath, mode=0777, intermediate=False):
        remotepath = self.normalize_dirpath(remotepath)
        if intermediate:
            try:
                sftp.mkdir(remotepath, mode=mode)
            except IOError, e:
                self.mkdir(sftp, remotepath.rsplit("/", 1)[0], mode=mode,
                           intermediate=True)
                return sftp.mkdir(remotepath, mode=mode)
        else:
            sftp.mkdir(remotepath, mode=mode)


    def put_dir_recursively(self,  localpath, remotepath, preserve_perm=True):
        "upload local directory to remote recursively"

        assert remotepath.startswith("/"), "%s must be absolute path" % remotepath

        # normalize
        localpath = self.normalize_dirpath(localpath)
        remotepath = self.normalize_dirpath(remotepath)

        sftp = self.client.open_sftp()

        try:
            sftp.chdir(remotepath)
            localsuffix = localpath.rsplit("/", 1)[1]
            remotesuffix = remotepath.rsplit("/", 1)[1]
            if localsuffix != remotesuffix:
                remotepath = os.path.join(remotepath, localsuffix)
        except IOError, e:
            pass

        for root, dirs, fls in os.walk(localpath):
            prefix = os.path.commonprefix([localpath, root])
            suffix = root.split(prefix, 1)[1]
            if suffix.startswith("/"):
                suffix = suffix[1:]

            remroot = os.path.join(remotepath, suffix)

            try:
                sftp.chdir(remroot)
            except IOError, e:
                if preserve_perm:
                    mode = os.stat(root).st_mode & 0777
                else:
                    mode = 0777
                self.mkdir(sftp, remroot, mode=mode, intermediate=True)
                sftp.chdir(remroot)

            for f in fls:
                remfile = os.path.join(remroot, f)
                localfile = os.path.join(root, f)
                sftp.put(localfile, remfile)
                if preserve_perm:
                    sftp.chmod(remfile, os.stat(localfile).st_mode & 0777)

You might replace sftp = self.client.open_sftp() with paramiko's one and get rid of libcloud here.

import os.path
from stat import S_ISDIR
from libcloud.compute.ssh import SSHClient
from paramiko.sftp import SFTPError

class CloudSSHClient(SSHClient):


    @staticmethod
    def normalize_dirpath(dirpath):
        while dirpath.endswith("/"):
            dirpath = dirpath[:-1]
        return dirpath


    def mkdir(self, sftp, remotepath, mode=0777, intermediate=False):
        remotepath = self.normalize_dirpath(remotepath)
        if intermediate:
            try:
                sftp.mkdir(remotepath, mode=mode)
            except IOError, e:
                self.mkdir(sftp, remotepath.rsplit("/", 1)[0], mode=mode,
                           intermediate=True)
                return sftp.mkdir(remotepath, mode=mode)
        else:
            sftp.mkdir(remotepath, mode=mode)


    def put_dir_recursively(self,  localpath, remotepath, preserve_perm=True):
        "upload local directory to remote recursively"

        assert remotepath.startswith("/"), "%s must be absolute path" % remotepath

        # normalize
        localpath = self.normalize_dirpath(localpath)
        remotepath = self.normalize_dirpath(remotepath)

        sftp = self.client.open_sftp()

        try:
            sftp.chdir(remotepath)
            localsuffix = localpath.rsplit("/", 1)[1]
            remotesuffix = remotepath.rsplit("/", 1)[1]
            if localsuffix != remotesuffix:
                remotepath = os.path.join(remotepath, localsuffix)
        except IOError, e:
            pass

        for root, dirs, fls in os.walk(localpath):
            prefix = os.path.commonprefix([localpath, root])
            suffix = root.split(prefix, 1)[1]
            if suffix.startswith("/"):
                suffix = suffix[1:]

            remroot = os.path.join(remotepath, suffix)

            try:
                sftp.chdir(remroot)
            except IOError, e:
                if preserve_perm:
                    mode = os.stat(root).st_mode & 0777
                else:
                    mode = 0777
                self.mkdir(sftp, remroot, mode=mode, intermediate=True)
                sftp.chdir(remroot)

            for f in fls:
                remfile = os.path.join(remroot, f)
                localfile = os.path.join(root, f)
                sftp.put(localfile, remfile)
                if preserve_perm:
                    sftp.chmod(remfile, os.stat(localfile).st_mode & 0777)
病女 2024-10-13 21:16:28

我认为你做不到。查找 os.walk 的文档并“手动”复制每个文件。

I don't think you can do that. Look up the documentation for os.walk and copy each file "manually".

橙味迷妹 2024-10-13 21:16:28

这是我在 StackOverflow 上的第一个回答。我今天有一个与此类似的任务。因此,我尝试找到一种使用 python 和 paramiko 将整个文件夹从 Windows 复制到 Linux 的直接方法。经过一番研究,我想出了这个解决方案,适用于其中包含子文件夹和文件的较小尺寸的文件夹。

该解决方案首先为当前文件夹制作 zip 文件(os.walk() 在这里非常有帮助),然后复制到目标服务器并在那里解压缩。

zipHere = zipfile.ZipFile("file_to_copy.zip", "w")

for root, folders, files in os.walk(FILE_TO_COPY_PATH):
    for file in files:
        zipHere.write(os.path.join(root, file), arcname=os.path.join(os.path.relpath(root, os.path.dirname(FILE_TO_COPY_PATH)), file))
    for folder in folders:
        zipHere.write(os.path.join(root, folder), arcname=os.path.join(os.path.relpath(root, os.path.dirname(FILE_TO_COPY_PATH)), folder))
zipHere.close()

# sftp is the paramiko.SFTPClient connection
sftp.put('local_zip_file_location','remote_zip_file_location')

# telnet_conn is the telnetlib.Telnet connection
telnet_conn.write('cd cd_to_zip_file_location')
telnet_conn.write('unzip -o file_to_copy.zip')

This is my first StackOverflow answer. I had a task today which is similar to this. So, I tried to find a direct way to copy entire folder from windows to linux using python and paramiko. After a little research, I came up with this solution which works for smaller size folders with subfolders and files in it.

This solution first makes the zip file for the current folder (os.walk() is very much helpful here), then copies to destination server and unzip there.

zipHere = zipfile.ZipFile("file_to_copy.zip", "w")

for root, folders, files in os.walk(FILE_TO_COPY_PATH):
    for file in files:
        zipHere.write(os.path.join(root, file), arcname=os.path.join(os.path.relpath(root, os.path.dirname(FILE_TO_COPY_PATH)), file))
    for folder in folders:
        zipHere.write(os.path.join(root, folder), arcname=os.path.join(os.path.relpath(root, os.path.dirname(FILE_TO_COPY_PATH)), folder))
zipHere.close()

# sftp is the paramiko.SFTPClient connection
sftp.put('local_zip_file_location','remote_zip_file_location')

# telnet_conn is the telnetlib.Telnet connection
telnet_conn.write('cd cd_to_zip_file_location')
telnet_conn.write('unzip -o file_to_copy.zip')
森林迷了鹿 2024-10-13 21:16:28

Paramiko 本身不支持目录传输。正如此处许多现有答案所示,您必须实施它。

您可以检查 pysftp 代码。它是 Paramiko 的包装器,支持递归操作。请参阅

我不建议直接使用pysftp代码(pysftp vs. Paramiko )但是,因为它不再维护并且有一些错误。对于基于 pysftp 的独立可移植仅 Paramiko 代码,请参阅我的答案:

Paramiko does not support directory transfers on its own. You have to implement it, as many existing answers here show.

You can check pysftp code. It's a wrapper around Paramiko that supports recursive operations. See

I do not recommend using pysftp code directly (pysftp vs. Paramiko) though, as it is not maintained anymore and has some bugs. For working standalone portable Paramiko-only code based on pysftp see my answers to:

一个人练习一个人 2024-10-13 21:16:28

我的回答和上面类似,只是列一个清单,然后一项一项地转移。

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='11.11.11.1111', username='root', password='********', port=22)
sftp_client = ssh.open_sftp()
source_folder = '/var/ftp/file_pass'
local_folder = 'C:/temp/file_pass'
inbound_files = sftp_client.listdir(source_folder)
print(inbound_files)

for ele in inbound_files:
    try:
        path_from = source_folder + '/' + ele
        path_to = local_folder + '/'+ ele
        sftp_client.get(path_from, path_to)
    except:
        print(ele)

sftp_client.close()
ssh.close()

my answer is similar with above just make a list, and then transfer one by one.

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='11.11.11.1111', username='root', password='********', port=22)
sftp_client = ssh.open_sftp()
source_folder = '/var/ftp/file_pass'
local_folder = 'C:/temp/file_pass'
inbound_files = sftp_client.listdir(source_folder)
print(inbound_files)

for ele in inbound_files:
    try:
        path_from = source_folder + '/' + ele
        path_to = local_folder + '/'+ ele
        sftp_client.get(path_from, path_to)
    except:
        print(ele)

sftp_client.close()
ssh.close()
违心° 2024-10-13 21:16:28

这是我的方法,但是代码也处理隐藏文件

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("localhost", port=19000, username="test", password="test")
sftp = ssh.open_sftp()

source_folder="/etc/"
inbound_files=sftp.listdir(source_folder)


for file in inbound_files :
    filepath = source_folder+file
    localpath = "/home/"+file
    # check hidden files
    if file.startswith('.'):
        pass
    else:
        sftp.get(filepath, localpath)
    

This is my approach but and the code handle hidden files also

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("localhost", port=19000, username="test", password="test")
sftp = ssh.open_sftp()

source_folder="/etc/"
inbound_files=sftp.listdir(source_folder)


for file in inbound_files :
    filepath = source_folder+file
    localpath = "/home/"+file
    # check hidden files
    if file.startswith('.'):
        pass
    else:
        sftp.get(filepath, localpath)
    
安稳善良 2024-10-13 21:16:28

根据 skoll 投票最高的答案,我提出了一个可能更高级别的解决方案(递归是一个选项;有返回值;如果是一个文件可以是目录或文件名)并且现代(类型提示;pathlib):

from pathlib import Path

import paramiko
from paramiko.common import o777


def mkdir(client: paramiko.SFTP, path: Path | str, mode: int = o777, exists_ok: bool = False) -> None:
    """Augments mkdir by adding an option to not fail if the folder exists"""
    try:
        client.mkdir(str(path), mode)
    except IOError as err:
        if exists_ok:
            pass
        else:
            raise err


def upload(
    client: paramiko.SFTP, local_path: Path | str, remote_path: Path | str, recursive: bool = False
) -> paramiko.SFTPAttributes | list[paramiko.SFTPAttributes]:
    """
    Upload file (or directory if <recursive> is True) to a remote path.

    The correct uploading of files is verified by examining their sizes.
    """

    local_path = Path(local_path)
    remote_path = Path(remote_path)

    if recursive and local_path.is_dir():
        mkdir(client, remote_path / local_path.name, exists_ok=True)
        return [upload(client, sub_path, remote_path / local_path.name, recursive) for sub_path in local_path.iterdir()]
    else:
        try:
            return client.put(str(local_path), str(remote_path))
        except OSError as err:
            if str(err) == "Specified file is a directory." and local_path.is_file():
                return client.put(str(local_path), str(remote_path / local_path.name))
            raise err

Based on the top voted answer by skoll, I made a solution that may be more high-level (recursive is an option; has return values; if <local_path> is a file <remote_path> can be a directory or filename) and modern (type hints; pathlib):

from pathlib import Path

import paramiko
from paramiko.common import o777


def mkdir(client: paramiko.SFTP, path: Path | str, mode: int = o777, exists_ok: bool = False) -> None:
    """Augments mkdir by adding an option to not fail if the folder exists"""
    try:
        client.mkdir(str(path), mode)
    except IOError as err:
        if exists_ok:
            pass
        else:
            raise err


def upload(
    client: paramiko.SFTP, local_path: Path | str, remote_path: Path | str, recursive: bool = False
) -> paramiko.SFTPAttributes | list[paramiko.SFTPAttributes]:
    """
    Upload file (or directory if <recursive> is True) to a remote path.

    The correct uploading of files is verified by examining their sizes.
    """

    local_path = Path(local_path)
    remote_path = Path(remote_path)

    if recursive and local_path.is_dir():
        mkdir(client, remote_path / local_path.name, exists_ok=True)
        return [upload(client, sub_path, remote_path / local_path.name, recursive) for sub_path in local_path.iterdir()]
    else:
        try:
            return client.put(str(local_path), str(remote_path))
        except OSError as err:
            if str(err) == "Specified file is a directory." and local_path.is_file():
                return client.put(str(local_path), str(remote_path / local_path.name))
            raise err
仲春光 2024-10-13 21:16:28

据我所知,Paramiko 不支持递归文件上传。但是,我发现了 此处使用 Paramiko 进行递归上传的解决方案。以下是他们的递归上传函数的摘录:

   def _send_recursive(self, files):
        for base in files:
            lastdir = base
            for root, dirs, fls in os.walk(base):
                # pop back out to the next dir in the walk
                while lastdir != os.path.commonprefix([lastdir, root]):
                    self._send_popd()
                    lastdir = os.path.split(lastdir)[0]
                self._send_pushd(root)
                lastdir = root
                self._send_files([os.path.join(root, f) for f in fls])

您可以尝试使用他们的函数 SCPClient.put 调用上述函数进行递归上传,或者自行实现。

As far as I know, Paramiko does not support recursive file upload. However, I have found a solution for recursive upload using Paramiko here. Follows an excerpt of their recursive upload function:

   def _send_recursive(self, files):
        for base in files:
            lastdir = base
            for root, dirs, fls in os.walk(base):
                # pop back out to the next dir in the walk
                while lastdir != os.path.commonprefix([lastdir, root]):
                    self._send_popd()
                    lastdir = os.path.split(lastdir)[0]
                self._send_pushd(root)
                lastdir = root
                self._send_files([os.path.join(root, f) for f in fls])

You may try to either use their function SCPClient.put invoking the above function for recursive upload or implement it on your own.

原谅过去的我 2024-10-13 21:16:28

如果您想对每个文件夹进行并行复制,可以使用(请记住,它将忽略本地已存在的文件):

def get_folders(sftp_client, remote_dir, local_dir):
    if not exists_remote(sftp_client, remote_dir):
        return

    if not os.path.exists(local_dir):
        os.mkdir(local_dir)

    for filename in sftp_client.listdir(remote_dir):
        remote_dir_path = f"{remote_dir}/{filename}"
        print(f"downloading {remote_dir_path}")
        current_stat = sftp_client.stat(remote_dir_path)
        if stat.S_ISDIR(current_stat.st_mode):
            get_folders(sftp_client, remote_dir_path, os.path.join(local_dir, filename))
        else:
            if not os.path.isfile(os.path.join(local_dir, filename)):
                sftp_client.get(remote_dir_path, os.path.join(local_dir, filename))


def exists_remote(sftp_client, path):
    try:
        sftp_client.stat(path)
    except IOError as e:
        if e.errno == errno.ENOENT:
            return False
        raise
    else:
        return True


def copy_from_server(dir_path):
    import paramiko

    server = "A"
    username = "B"
    password = "C"
    remote_path = ""
    local_path = ""

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(server, username=username, password=password)
    sftp = ssh.open_sftp()
    print("connected")
    get_folders(sftp, f"{remote_path}/{dir_path}",
                   rf"{local_path}\{dir_path}")
    print("downloaded")
    sftp.close()
    ssh.close()


def parallel_copy_from_server():
    dir_names = ['A', 'B']
    NUM_OF_CPUS = multiprocessing.cpu_count()
    with Pool(NUM_OF_CPUS) as p:
        results_list = p.map(copy_from_server, dir_names)

If you would like to have parallel copy per folder you can use (keep in mind that it will ignore files that already exists localy):

def get_folders(sftp_client, remote_dir, local_dir):
    if not exists_remote(sftp_client, remote_dir):
        return

    if not os.path.exists(local_dir):
        os.mkdir(local_dir)

    for filename in sftp_client.listdir(remote_dir):
        remote_dir_path = f"{remote_dir}/{filename}"
        print(f"downloading {remote_dir_path}")
        current_stat = sftp_client.stat(remote_dir_path)
        if stat.S_ISDIR(current_stat.st_mode):
            get_folders(sftp_client, remote_dir_path, os.path.join(local_dir, filename))
        else:
            if not os.path.isfile(os.path.join(local_dir, filename)):
                sftp_client.get(remote_dir_path, os.path.join(local_dir, filename))


def exists_remote(sftp_client, path):
    try:
        sftp_client.stat(path)
    except IOError as e:
        if e.errno == errno.ENOENT:
            return False
        raise
    else:
        return True


def copy_from_server(dir_path):
    import paramiko

    server = "A"
    username = "B"
    password = "C"
    remote_path = ""
    local_path = ""

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(server, username=username, password=password)
    sftp = ssh.open_sftp()
    print("connected")
    get_folders(sftp, f"{remote_path}/{dir_path}",
                   rf"{local_path}\{dir_path}")
    print("downloaded")
    sftp.close()
    ssh.close()


def parallel_copy_from_server():
    dir_names = ['A', 'B']
    NUM_OF_CPUS = multiprocessing.cpu_count()
    with Pool(NUM_OF_CPUS) as p:
        results_list = p.map(copy_from_server, dir_names)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文