为什么QtNetwork.QFtp.get下载在多个文件的for循环中失败?
我正在尝试使用for-loop从ftp站点下载多个文件。在弹出python.exe关闭窗口之前,下面的代码似乎只适用于循环中的前两个文件。两个下载的文件是完美的,但第三个下载的文件在关机时是空的。我没有得到其余的文件。任何想法可能是什么问题?为什么QtNetwork.QFtp.get下载在多个文件的for循环中失败?
from PyQt4 import QtCore, QtGui, QtNetwork
class FtpWindow(QtGui.QDialog):
def __init__(self, parent=None):
self.fileList = QtGui.QTreeWidget()
self.ftp = QtNetwork.QFtp(self)
self.progressDialog = QtGui.QProgressDialog(self)
self.downloadAllButton.clicked.connect(self.downloadAllFile)
self.ftp.commandFinished.connect(self.ftpCommandFinished)
def downloadAllFile(self):
for jj in range(self.fileList.topLevelItemCount()): # how many files in a particular folder
fileName = self.fileList.topLevelItem(jj).text(0)
self.outFile = QtCore.QFile(fileName)
self.ftp.get(fileName, self.outFile) #download one file at a time
self.progressDialog.setLabelText("Downloading %s..." % fileName)
self.progressDialog.exec_()
def ftpCommandFinished(self, _, error):
self.setCursor(QtCore.Qt.ArrowCursor)
if self.ftp.currentCommand() == QtNetwork.QFtp.Get:
if error:
self.statusLabel.setText("Canceled download of %s." % self.outFile.fileName())
self.outFile.close()
self.outFile.remove()
else:
self.statusLabel.setText("Downloaded %s to current directory." % self.outFile.fileName())
self.outFile.close()
self.outFile = None
self.enableDownloadButton()
self.progressDialog.hide()
self.progressDialog.exec_()
应该是一个阻塞模态对话框。使用self.progressDialog.show()
进行非阻塞呼叫。
它看起来像ftp get是非阻塞的,所以你必须等到使用commandFinished()信号完成下载。
我的猜测是循环中的每个迭代都覆盖self.outFile,因此没有任何对该对象的Python引用。这使得对象在Python执行垃圾回收时死亡。我的猜测是,你的前两个文件小而快,你的第三个文件更大,所以其他文件能够在垃圾回收之前下载。对于最后一个文件,这个或垃圾收集只是更快。
class FtpWindow(QtGui.QDialog):
def __init__(self, parent=None):
self.fileList = QtGui.QTreeWidget()
self.ftp = QtNetwork.QFtp(self)
self.progressDialog = QtGui.QProgressDialog(self)
self.progressDialog.canceled.connect(self.ftp.abort)
self.downloadAllButton.clicked.connect(self.downloadAllFile)
self.ref_holder = {}
self.ftp.commandFinished.connect(self.ftpCommandFinished)
def download_file(self, filename):
"""Non blocking start downloading a file."""
outFile = QtCore.QFile(filename)
cmd_id = self.ftp.get(filename, outFile) # Non blocking just start downloading
# This keeps the object alive and doesn't overwrite them.
self.ref_holder[cmd_id] = [filename, outFile]
def downloadAllFile(self):
self.progressDialog.reset()
num_downloads = self.fileList.topLevelItemCount()
self.progressDialog.setMaximum(num_downloads)
self.progressDialog.setValue(0)
self.progressDialog.setLabelText("Downloading %d files ..." % num_downloads)
self.progressDialog.show()
for jj in range(num_downloads): # how many files in a particular folder
fileName = self.fileList.topLevelItem(jj).text(0)
self.download_file(fileName) # Non blocking, and doesn't overwrite self.outFile with every iteration
def ftpCommandFinished(self, cmd_id, error=None):
"""Increased the number of items finished."""
self.progressDialog.setValue(self.progressDialog.value()+1)
item = self.ref_holder.pop(cmd_id) # Remove the reference for the finished item
if error:
self.progressDialog.setLabelText("Error downloading %s" % item[0])
# Check if all downloads are done
if len(self.ref_holder) == 0:
self.progressDialog.setValue(self.progressDialog.maximium())
self.progressDialog.close() # This shouldn't be needed
我的例子,直到命令完成上述将持有的文件名和不过outFile对象引用。当命令完成时,引用被删除,允许python清理对象。
文件感谢很多为您的代码,它的作品!但是,我发现即使处理下载,文件也不会显示在本地目标中。我必须添加“self.outFile.open(QtCore.QIODevice.WriteOnly)”来启用本地下载和保存。为什么?我已经包含我的版本 – Curiosity
感谢HashSplat的输入。我有几个更新,使其功能齐全:
class FtpWindow(QtGui.QDialog):
def __init__(self, parent=None):
self.fileList = QtGui.QTreeWidget()
self.ftp = QtNetwork.QFtp(self)
self.progressDialog = QtGui.QProgressDialog(self)
self.progressDialog.canceled.connect(self.ftp.abort)
self.downloadAllButton.clicked.connect(self.downloadAllFile)
self.ref_holder = {}
self.ftp.commandFinished.connect(self.ftpCommandFinished)
def download_file(self, fileName):
"""Non blocking start downloading a file."""
self.outFile = QtCore.QFile(fileName)
""" Need this to have files saved locally """
if not self.outFile.open(QtCore.QIODevice.WriteOnly):
QtGui.QMessageBox.information(self, "FTP",
"Unable to save the file %s." % fileName)
self.outFile = None
return
cmd_id = self.ftp.get(filename, self.outFile) # Non blocking just start downloading
# This keeps the object alive and doesn't overwrite them.
self.ref_holder[cmd_id] = [filename, self.outFile]
def downloadAllFile(self):
self.progressDialog.reset()
self.num_downloads = self.fileList.topLevelItemCount()
self.counter=1
self.progressDialog.setLabelText("Downloading %d/%d files ..." % (self.counter, self.num_downloads))
self.progressDialog.show()
for jj in range(num_downloads): # how many files in a particular folder
fileName = self.fileList.topLevelItem(jj).text(0)
self.download_file(fileName) # Non blocking, and doesn't overwrite self.outFile with every iteration
def ftpCommandFinished(self, cmd_id, error=None):
"""Increased the number of items finished."""
self.progressDialog.setValue(self.progressDialog.value()+1)
item = self.ref_holder.pop(cmd_id) # Remove the reference for the finished item
if error:
self.progressDialog.setLabelText("Error downloading %s" % item[0])
# Check if all downloads are done
if len(self.ref_holder) == 0:
self.progressDialog.close() # This closes the extra window
self.outFile.close() # You need this to have the last file saved
else:
self.counter+=1
self.progressDialog.setLabelText("Downloading %d/%d files ..." % (self.counter, self.num_downloads))
def updateDataTransferProgress(self, readBytes, totalBytes):
self.progressDialog.setMaximum(totalBytes)
self.progressDialog.setValue(readBytes)
在ftpCommandFinished where self.outFile.close()#你需要这个保存最后一个文件。您应该在if语句之前移动它,并关闭每个outFile。 'item [1] .close()#关闭outFile''if len(self.ref_holder)== 0:...' – HashSplat
我需要更多的代码来告诉。 'self.progressDialog.exec _()'应该是一个阻塞模态对话框。它看起来像ftp get是非阻塞的,所以你必须等到使用commandFinished()信号完成下载。覆盖outFile变量可能会导致问题。 http://pyside.github.io/docs/pyside/PySide/QtNetwork/QFtp.html#PySide.QtNetwork.PySide.QtNetwork.QFtp.get – HashSplat
@HashSplat,我用:self.progressDialog = QtGui.QProgressDialog(self) 。 – Curiosity
@HashSplat基本上,我试图创建一个单一的点击下载所有基于[此版本](http://*.com/questions/1995046/creating-an-ftp-client-with-python) – Curiosity