博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python使用paramiko的SFTP get或put整个目录
阅读量:4482 次
发布时间:2019-06-08

本文共 5866 字,大约阅读时间需要 19 分钟。

  在《》中举例说明了执行远程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主机上指定目录及其子目录下的所有文件的方法,也是定义在上面的类中的。

# ------获取远端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

  在上面的方法中,参数sftp表示已经建立的sftp连接,remote_dir是要扫描的远端目录。

  在扫描目录的时候,使用的listdir_attr方法会列出指定目录下的所有文件或目录,并且还会列出其属性,比如st_size,st_uid,st_gid,st_mode,st_atime,st_mtime,

  这些属性与linux中的stat函数返回的属性类似,我们就是根据其中的st_mode属性来判断是一个目录还是文件,并且处理st_mode的方法(位于stat模块中)也是与linux中定义的宏一致的。

  获取到指定目录下的所有文件之后,传输就比较简单了,依次遍历get即可:

def sftp_get_dir(self, remote_dir, local_dir):        t = paramiko.Transport(sock=(self.ip, 22))        t.connect(username=self.username, password=self.password)        sftp = paramiko.SFTPClient.from_transport(t)        # 获取远端linux主机上指定目录及其子目录下的所有文件        all_files = self.__get_all_files_in_remote_dir(sftp, remote_dir)        # 依次get每一个文件        for x in all_files:            filename = x.split('/')[-1]            local_filename = os.path.join(local_dir, filename)            print u'Get文件%s传输中...' % filename            sftp.get(x, local_filename)

  上面方法将remote_dir目录中的所有文件都get到了本地local_dir目录中,但是在本地没有保持与远端一致的目录结构,只是简单将所有文件保存在local_dir目录中。

  如果要保持与远端的目录结构一致,就需要在本地ocal_dir中创建子目录,这里暂且不讲述了,如有这种需求可思考一下。

 

  下面再来看看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目录中每一个文件或目录的完整路径            filename = os.path.join(local_dir, x)            # 如果是目录,则递归处理该目录            if os.path.isdir(x):                all_files.extend(self.__get_all_files_in_local_dir(filename))            else:                all_files.append(filename)        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 = remote_dir + '/' + filename            print u'Put文件%s传输中...' % filename            sftp.put(x, remote_filename)

  测试代码如下:

if __name__ == '__main__':    remote_path = r'/home/sea'    local_path = r'E:\PythonFiles\Learn\testsftp'    host = Linux('192.168.180.128', 'root', '1234')    # 将远端remote_path目录中的所有文件get到本地local_path目录    host.sftp_get_dir(remote_path, local_path)    # # 将本地local_path目录中的所有文件put到远端remote_path目录    # host.sftp_put_dir(remote_path, local_path)# 运行结果Get文件.profile传输中...Get文件.inputrc传输中...Get文件.emacs传输中...Get文件.bash_history传输中...Get文件.bashrc传输中...

转载:https://www.cnblogs.com/haigege/p/5517422.html#undefined

转载于:https://www.cnblogs.com/chen/p/9493546.html

你可能感兴趣的文章
html如何与cgi数据交换,HTML网页与CGI之间通信的 实例分析
查看>>
html如何调用flash插件,htmlflash播放器插件如何播放 网页播放器flash插件怎么解决...
查看>>
mysql数据在html上面显示不出来的,HTML表格不能正确显示MySQL数据
查看>>
数据包和html,数据包和数据报有何区别?
查看>>
jq 异步调用一个html,聊聊如何将jQuery的$.ajax()用于异步HTTP请求
查看>>
android 7.0宽度432,全球最小的4G手机,比手掌还小,安卓7.0
查看>>
android fragmentstatepageradapter框架,Android FragmentStatePagerAdapter
查看>>
html自适应meta标签,自适应布局meta标签中viewport、content、width、initial-scale、minimum-scale、maximum-scale总结...
查看>>
html怎么加入编辑器,HTML 编辑器
查看>>
python发挥程度_你为什么用 Python?
查看>>
file 选择的文件胖多有多大_「HTML5 进阶」FileAPI 文件操作实战,内附详细案例,建议收藏...
查看>>
玄惭 mysql_阿里云数据库专家玄惭的“武功”全记录之最佳实践、双十一特别篇...
查看>>
c mysql 时间段查询_mySql 时间段查询
查看>>
mysql sql乱码怎么解决_MYSQL数据库导入SQL文件出现乱码如何解决
查看>>
mysql的存储过程与事务_mysql的存储过程与事务入门
查看>>
java程序员闯关题网站_Java程序员每周必逛的十大学习网站
查看>>
python面试装饰器_Python测开面试题之装饰器
查看>>
flashcache mysql_flashcache的实现与分析
查看>>
linux shell 里面执行python 程序_Linux下编写脚本Shell和Python的区别?
查看>>
python中if elif语句优化_python – 最有效的方式做一个if-elif-elif-else语句当else做的最多?...
查看>>