Python通过paramiko复制本地目录到远程Linux主机(转载并修改Bug的高可用性版本)

转载至博客园博主的文章:https://www.cnblogs.com/haigege/p/5517422.html

但调试发现博主的代码还有一些问题,无法实现递归

原文:

使用paramiko的SFTP get或put整个目录

  在《使用paramiko执行远程linux主机命令》中举例说明了执行远程linux主机命令的方法,其实paramiko还支持SFTP传输文件。

  由于get或put方法每次只能传输一个文件,而不是整个目录,因此我们先看一下传输单个文件的方法,其实非常简单,网上也有很多参考资料了。

  还是直接使用前文中定义的类,我们添加两个方法即可(本文中不需要使用的方法先用pass代替了):

# 定义一个类,表示一台远端linux主机
class Linux(object):
    # 通过IP, 用户名,密码,超时时间初始化一个远程Linux主机
    def __init__(self, ip, username, password, timeout=30):
        self.ip = ip
        self.username = username
        self.password = password
        self.timeout = timeout
        # transport和chanel
        self.t = ''
        self.chan = ''
        # 链接失败的重试次数
        self.try_times = 3

    # 调用该方法连接远程主机
    def connect(self):
         pass

    # 断开连接
    def close(self):
        pass

    # 发送要执行的命令
    def send(self, cmd):
        pass

    # get单个文件
    def sftp_get(self, remotefile, localfile):
        t = paramiko.Transport(sock=(self.ip, 22))
        t.connect(username=self.username, password=self.password)
        sftp = paramiko.SFTPClient.from_transport(t)
        sftp.get(remotefile, localfile)
        t.close()

    # put单个文件
    def sftp_put(self, localfile, remotefile):
        t = paramiko.Transport(sock=(self.ip, 22))
        t.connect(username=self.username, password=self.password)
        sftp = paramiko.SFTPClient.from_transport(t)
        sftp.put(localfile, remotefile)
        t.close()

  注意上面的remotefile, localfile一定是文件,不能是目录,对于sftp_get,localfile指定本地将要保存的文件名,可以与remotefile的名字不一样;

  而sftp_put中,remotefile指定远端将要保存的文件名,可与localfile的名字不一样,测试代码如下:

if __name__ == '__main__':
    remotefile = r'/home/sea/test/xxoo.txt'
    localfile = r'E:\PythonFiles\Learn\ooxx.txt'

    host = Linux('192.168.180.128', 'root', '1234')

    # 将远端的xxoo.txt get到本地,并保存为ooxx.txt
    host.sftp_get(remotefile, localfile)

    # # 将本地的xxoo.txt put到远端,并保持为xxoo.txt
    # host.sftp_put(localfile, remotefile)

  

  下面再来考虑下如何传输整个目录?

  有两种思路:

  1 如果是要get则采用已经定义的connect方法连接到linux主机,然后通过send方法执行tar命令将需要传输的整个目录打包,再传输打包后的文件即可,如果是put则需在本地打包

        该方法的缺点是:在远端或者本地进行打包或者解压,并且打包会占用临时存储空间,如果是远端打包还需先SSH链接linux主机。

        优点是:不用做目录扫描处理。

      2 遍历需要get或put的目录及其子目录,然后依次传输每一个文件。优点是不需要SSH登陆和打包解压,缺点是需要做目录扫描,但是目录扫描是很简单的,因此我们采用这种方法。

  先来看看Get,由于要扫描目录,因此先定义一个方法用来对指定目录进行扫描,找出该目录及所有子目录中的所有文件。

  那么问题来了,怎么扫描目录呢?使用python的os库的方法吗?肯定是不行的,因为python的os库的方法都是对本地目录或文件的操作,它是无法操作远程linux主机上的文件和目录的。

  其实paramiko的SFTP接口提供了操作远端linux主机上的文件和目录的方法,只要建立了与远端的SFTP连接后,就可以执行文件和目录操作。

  

# ------获取远端linux主机上指定目录及其子目录下的所有文件------
    def __get_all_files_in_remote_dir(self, sftp, remote_dir):
        # 保存所有文件的列表
        all_files = list()

        # 去掉路径字符串最后的字符'/',如果有的话
        if remote_dir[-1] == '/':
            remote_dir = remote_dir[0:-1]

        # 获取当前指定目录下的所有目录及文件,包含属性值
        files = sftp.listdir_attr(remote_dir)
        for x in files:
            # remote_dir目录中每一个文件或目录的完整路径
            filename = remote_dir + '/' + x.filename
            # 如果是目录,则递归处理该目录,这里用到了stat库中的S_ISDIR方法,与linux中的宏的名字完全一致
            if S_ISDIR(x.st_mode):
                all_files.extend(self.__get_all_files_in_remote_dir(sftp, filename))
            else:
                all_files.append(filename)
        return all_files

       下面再来看看put,其实与get几乎一样,现在扫描本地目录,然后依次遍历文件并put到远端,

  由于是对本地目录做扫描,因此不需要调用SFTP中的文件目录处理接口了,直接使用python的os库即可,代码如下:

# ------获取本地指定目录及其子目录下的所有文件------
    def __get_all_files_in_local_dir(self, local_dir):
        # 保存所有文件的列表
        all_files = list()

        # 获取当前指定目录下的所有目录及文件,包含属性值
        files = os.listdir(local_dir)
        for x in files:
            # local_dir目录中每一个文件或目录的完整路径
            fullpath = os.path.join(local_dir, x)
            # 如果是目录,则递归处理该目录
            if os.path.isdir(fullpath):
                all_files.append(fullpath)
                all_files.extend(self.__get_all_files_in_local_dir(fullpath))
            else:
                all_files.append(fullpath)
        return all_files

    def sftp_put_dir(self, local_dir, remote_dir):
        t = paramiko.Transport(sock=(self.ip, 22))
        t.connect(username=self.username, password=self.password)
        sftp = paramiko.SFTPClient.from_transport(t)

        # 去掉路径字符穿最后的字符'/',如果有的话
        if remote_dir[-1] == '/':
            remote_dir = remote_dir[0:-1]

        # 获取本地指定目录及其子目录下的所有文件
        all_files = self.__get_all_files_in_local_dir(local_dir)
        # 依次put每一个文件
        for x in all_files:
            filename = os.path.split(x)[-1]
            remote_filename = x.replace(local_path,remote_path) 
            remote_filename = remote_filename.replace("\\","/")
            if os.path.isdir(x):
                sftp.mkdir(remote_filename)
                print(u'Put文件夹%s创建中...' % filename)
                continue
            else:
                print(u'Put文件%s传输中...' % filename)
                sftp.put(x, remote_filename)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值