Python FTP文件傳輸實現


  1. FTP一般流程

 FTP對應PASV和PORT兩種訪問方式,分別為被動和主動,是針對FTP服務器端進行區分的,正常傳輸過程中21號端口用於指令傳輸,數據傳輸端口使用其他端口。

PASV:由客戶端發起數據傳輸請求,服務器端返回並攜帶數據端口,並且服務器端開始監聽此端口等待數據,為被動模式;

PORT:客戶端監聽端口並向服務器端發起請求,服務器端主動連接此端口進行數據傳輸,為主動模式。

其中TYPE分兩種模式,I對應二進制模式、A對應ASCII模式;

PASV為客戶端發送請求,之后227為服務器端返回操作碼表示成功,並且后面帶有服務器端監聽的端口:143x256(左移8位)+48

之后通過STOR命令進行數據下載,下載完成后返回226表示數據傳輸完成。

  2. Python代碼實現:

中文路徑問題:由於FTP支持ASCII編碼,Python ftplib中編碼方式使用latin-1,而window默認編碼方式為gbk,所以使用Python處理時需先將中文路徑編碼為gbk之后譯碼為latin-1字符;

上傳下載使用storline和retrline,對應二進制使用storbinary和retrbinary。對於stor類函數后面的參數fp表示接收一個文件對象,支持read方法,一般為打開需要上傳的源文件,而retr類函數后面的參數表示對於返回數據的處理方法。

從一個FTP服務器到另一個FTP服務器的數據傳輸:

利用本地電腦作為數據緩存,但並不將數據保存到硬盤,只在內存中存儲進行數據傳輸;其中一端作為下載一端為數據上傳。

首先登陸兩個FTP服務器,transfercmd函數用於發送命令並返回已建立好連接的本地Socket,此時分別在兩個本地Socket進行數據的收發即可。

在測試中發現,在發送完一個文件之后只有及時的關閉socket,21端口才會返回226,數據完成指示,這樣才可以循環下一個文件,在完成之后要退出FTP。

#coding=utf-8

import ftplib,os.path,os
import socket

f1=ftplib.FTP('172.16.2.76')
f2=ftplib.FTP('172.16.25.153')


class myFTP:
        path='file/download/bbb/'
        # ftplib中編碼使用latin-1
        title='版本'.encode(encoding='gbk').decode(encoding='latin-1')
        path1=path+title   
        localDir='E:\\ver\\fp\\'
        
        path2='abc/edf/'
        

        def __init__(self):
                      
            try:
                f1.login('username','password')
            except ftplib.error_perm:
                print('f1 cannot loggin!')
                return

            try:
                f2.login()
            except ftplib.error_perm:
                print('f2 cannot loggin!')
                return
                
        def ftpD(self):
                          
            filelist=[]
            fileLIST=[]
            filels=f1.retrlines('LIST %s'%(self.path1),callback=filelist.append)
            f1.cwd(self.path1)
            for file in filelist:
                fileAttr=file.split(' ')
                fileName=fileAttr[-1]
                fileType=fileAttr[0][0]
                if fileType=='-':
                    fileLIST.append(fileName)
        
            for file in fileLIST:
                path=self.localDir+file
                f1.retrbinary('RETR %s'%(file),open(path,'wb').write)
                print('%s download.....'%(file))        
            f1.quit()
        
        def ftpU(self,fun=1):
        
            os.chdir(self.localDir)
            fileList=os.listdir()
            
            # upload file
            if fun==1:
                    for file in fileList:
                        path=self.path2
                        f2.storbinary('STOR %s'%(path+file),open(file,'rb'))
                        print('%s uploading......'%(file))
            
            #delete file
            if fun==0:
                    try:
                            for file in fileList:
                                path=self.path2
                                f2.delete(path+file)
                                print('%s delete......'%(file))
                    except ftplib.error_perm:
                            print('no file to delete!!')
                            return
           
            f2.quit()
        
        def test(self):
            
            f1.cwd(self.path1)
            f2.cwd(self.path2)
            fileList=f1.nlst()
            print(fileList)
           
            for file in fileList:
                print('transfer %s......'%(file))
                f1.voidcmd('TYPE I')
                f2.voidcmd('TYPE I')
                sock1=f1.transfercmd('RETR %s'%(file))
                sock2=f2.transfercmd('STOR %s'%(file))
        
                while 1:
            
                        data=sock1.recv(1024)
                        sock2.sendall(data)
                        
                        if len(data)==0:
                            break
                # 數據發送完成后需關閉socket,服務器21端口才會有返回        
                sock1.close()
                sock2.close()
                        
                                                   
                res1=f1.getresp()
                #print('f1 >> %s'%(res1))
                res2=f2.getresp()
                #print('f2 >> %s'%(res2))       
                                     
            f1.quit()
            f2.quit()

        
if __name__=='__main__':
    ftptest=myFTP()  
    ftptest.ftpU(0)
    #ftptest.test()
    #ftptest.ftpD()
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM