[PyQt] FtpClient

Source: FtpClient.zip

這支程式只是純粹要實做圖形介面的Ftp客戶端程式,透過python的ftplib和Qt的widgets的組合產生了這麼一個簡易的FtpClient程式。


由於現在的Ftp還多了Http Ftp的型態,不像傳統的Ftp會有基本的"."以及".."(本目錄,前一目錄)的資料夾,面對這樣的情況就必須自行偵測並手動加上".."(parent directory)這個目錄。

for line in data:
    spline = line.split()
    if(spline[8][0] != '.' and self.flagParentDir == False):
        item = QtGui.QTreeWidgetItem()
        item.setText(0, '..')
        item.setText(1, '1024')
        item.setText(2, spline[2])
        item.setText(3, spline[3])
        item.setText(4, spline[0])
        item.setIcon(0, self.ui.folderIconBlue)
        self.ui.ftpTree.addTopLevelItem(item)
        self.flagParentDir = True
    else:
        self.flagParentDir = True

ftplib所提供的dir指令回傳回來的檔案結構如下:
['drwxr-xr-x', '4', '2000', '0', '512', 'Jun', '10', '21:20', 'Linux']

所以在處理treeitem時,必須注意一下index位置所對應的檔案類型,否則成列出來的資料就會錯亂。

item = QtGui.QTreeWidgetItem()
item.setText(0, spline[8])
item.setText(1, spline[4])
item.setText(2, spline[2])
item.setText(3, spline[3])
item.setText(4, spline[0])

上下傳的進度顯示方面則是搭配了retrbinary()以及storbinary()所接收的callback函式的格式,程式片段如下:
class TransferProgress:
    def __init__(self, pBar, filename, filesize, msg, file=None):
    
        # file descriptor will be used while downloding
        self.file = file
        
        self.totalSize = int(filesize)
        self.recvSize = 0
        
        self.pBar = pBar
        self.pBar.setWindowTitle(msg+filename)
        self.pBar.show()
        
    def uploadProgress(self, data):
        self.recvSize += len(data)
        self.pBar.setValue(self.recvSize*100 /self.totalSize)
        
    def downloadProgress(self, data):
        self.recvSize += len(data)
        self.file.write(data)
        self.pBar.setValue(self.recvSize*100 /self.totalSize)

建立了一個叫做TransferProgress的類別,裡面包含了uploadProgress(),downloadProgress()這兩個函式,分別對應到上傳和下載的進度顯示。要注意的是uploadProgress(),downloadProgress()它們都接收了一個名為data的變數,這個data變數裡面紀錄著每一次retrbinary()和storbinary()在傳送接收資料時的檔案資料區塊(可能是一個由ftplib所內定的buffersize),藉由這個data變數我們才能顯示檔案傳輸進度以及作資料存取。

def download(self, filename, filesize):
    filein = open(self.sysRootPath+'/'+filename, "wb")
    tp = FileTransfer.TransferProgress(self.ui.progressBar, filename, filesize, 'Download: ', filein)
    self.ftp.retrbinary("RETR " + filename, tp.downloadProgress, 1024)
    filein.close()
以下載為例,先建立一個檔案物件,再建立一個TransferProgress的物件tp,傳入tp.downloadProgress這個callback function給retrbinary函式,而檔案寫入的動作則是由callback過程中將data傳至downloadPorgress()裡,並於tp一開始建立所設定的檔案物件filein來寫入,整個上下傳部份顯得有點複雜了一些。

另外值得注意的是當你要從QString轉型到python string這個過程中必須要使用str()這個函式來做型態轉型,否則資料會解讀錯誤。反之,則不需要。
def onFtpItemDoubleClicked(self, item):
    permission = str(item.text(4))
    if(permission[0] == 'd'):
        self.ftp.cwd(str(item.text(0)))
    else:
        self.download(str(item.text(0)), str(item.text(1)))
    self.updateFtpFileList()
    
    
def onSysItemDoubleClicked(self, item):
    path = str(item.text(4))
    if(QtCore.QFileInfo(path).isDir()):
        self.sysRootPath = path
    else:
        self.upload(str(item.text(0)) ,path)
    self.updateSysFileList()

整個FtpClient只有實做到連線上下傳的部份,進一步的功能如續傳,進階檔案變更,往後有這個需要再來撰寫吧!

No comments:

Post a Comment

Orange - data analysis tool

Installation pip install orange3 Run orange python -m Orange.canvas