# 定義一個類,表示一臺遠端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