一、封装代码
import os import paramiko from stat import S_ISDIR import shutil class ConnectSftp(object): def __init__(self,ip,port,username,password): self.ip=ip self.port=port self.username=username self.password=password self.connect() def connect(self): self.transport = paramiko.Transport((self.ip, self.port)) self.transport.connect(username=self.username, password=self.password) self.sftp = paramiko.SFTPClient.from_transport(self.transport) def close(self): self.transport.close() def isdir(self,path): try: return S_ISDIR(self.sftp.stat(path).st_mode) except IOError: return False def sftp_rm(self,path): files = self.sftp.listdir(path=path) for f in files: filepath = os.path.join(path, f) if self.isdir(filepath): self.sftp_rm(filepath) else: self.sftp.remove(filepath) self.sftp.rmdir(path) def local_to_sftp(self,local_dir_name,remote_dir_name,move_state=False): ''' :param local_dir_name: 本地文件夹路径 :param remote_dir_name: sftp文件夹路径 :param move_state: 是否删除本地文件夹 :return: ''' if os.path.isdir(local_dir_name): # 文件夹,不能直接下载,需要继续循环 self.check_sftp_dir(remote_dir_name) for remote_file_name in os.listdir(local_dir_name): sub_local = os.path.join(local_dir_name, remote_file_name) sub_local = sub_local.replace('\', '/') sub_remote = os.path.join(remote_dir_name, remote_file_name) sub_remote = sub_remote.replace('\', '/') print(sub_local, sub_remote) self.local_to_sftp(sub_local, sub_remote) else: # 文件,直接上传 print('开始上传文件:' + local_dir_name) self.sftp.put(local_dir_name, remote_dir_name) if move_state: shutil.rmtree(local_dir_name) def sftp_to_local(self,remote_dir_name,local_dir_name,move_state=False): ''' :param remote_dir_name: sftp文件夹路径 :param local_dir_name: 本地文件夹路径 :param move_state: 是否删除sftp文件夹 :return: ''' try: self.sftp.stat(remote_dir_name) except Exception: raise BaseException({"error":"sftp路径不存在"}) remote_file = self.sftp.stat(remote_dir_name) if S_ISDIR(remote_file.st_mode): # 文件夹,不能直接下载,需要继续循环 self.check_local_dir(local_dir_name) print('开始下载文件夹:' + remote_dir_name) for remote_file_name in self.sftp.listdir(remote_dir_name): sub_remote = os.path.join(remote_dir_name, remote_file_name) sub_remote = sub_remote.replace('\', '/') sub_local = os.path.join(local_dir_name, remote_file_name) sub_local = sub_local.replace('\', '/') self.sftp_to_local(sub_remote, sub_local) else: # 文件,直接下载 print('开始下载文件:' + remote_dir_name) self.sftp.get(remote_dir_name, local_dir_name) if move_state: self.sftp_rm(remote_dir_name) def check_local_dir(self, local_dir_name): """本地文件夹是否存在,不存在则创建""" if not os.path.exists(local_dir_name): os.makedirs(local_dir_name) def check_sftp_dir(self, remote_dir_name): """sftp文件夹是否存在,不存在则创建""" try: self.sftp.stat(remote_dir_name) except IOError as e: self.sftp.mkdir(remote_dir_name) def cmd(self, command): ssh = paramiko.SSHClient() ssh._transport = self.transport stdin, stdout, stderr = ssh.exec_command(command) print(stdout) result = stdout.read() return result cs=ConnectSftp('ip',port,'name','pwd') if __name__ == '__main__': cs.local_to_sftp(r"本地路径",'sftp路径',move_state=True) cs.sftp_to_local("sftp路径",r"本地路径",move_state=True) cs.close()
二、解决windows2008-sftp文件路径乱码
找到paramiko下的py3compat文件,将以下4个函数内的编码改成‘gbk’
def b(s, encoding="gbk"): """cast unicode or bytes to bytes""" if isinstance(s, bytes): return s elif isinstance(s, str): return s.encode(encoding) else: raise TypeError("Expected unicode or bytes, got {!r}".format(s)) def u(s, encoding="gbk"): """cast bytes or unicode to unicode""" if isinstance(s, bytes): return s.decode(encoding) elif isinstance(s, str): return s else: raise TypeError("Expected unicode or bytes, got {!r}".format(s))
def b(s, encoding="gbk"): # NOQA """cast unicode or bytes to bytes""" if isinstance(s, str): return s elif isinstance(s, unicode): # NOQA return s.encode(encoding) elif isinstance(s, buffer): # NOQA return s else: raise TypeError("Expected unicode or bytes, got {!r}".format(s)) def u(s, encoding="gbk"): # NOQA """cast bytes or unicode to unicode""" if isinstance(s, str): return s.decode(encoding) elif isinstance(s, unicode): # NOQA return s elif isinstance(s, buffer): # NOQA return s.decode(encoding) else: raise TypeError("Expected unicode or bytes, got {!r}".format(s))