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只有實做到連線上下傳的部份,進一步的功能如續傳,進階檔案變更,往後有這個需要再來撰寫吧!