# 定义一个类,表示一台远端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的名字不同;bash
而sftp_put中,remotefile指定远端将要保存的文件名,可与localfile的名字不同,测试代码以下:app
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)
下面再来考虑下如何传输整个目录?函数
有两种思路:post
1 若是是要get则采用已经定义的connect方法链接到linux主机,而后经过send方法执行tar命令将须要传输的整个目录打包,再传输打包后的文件便可,若是是put则需在本地打包测试
该方法的缺点是:在远端或者本地进行打包或者解压,而且打包会占用临时存储空间,若是是远端打包还需先SSH连接linux主机。ui
优势是:不用作目录扫描处理。spa
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