Python QtNetwork-下载线程化文件

Python QtNetwork-下载线程化文件,python,download,pyqt4,qthread,qtnetwork,Python,Download,Pyqt4,Qthread,Qtnetwork,因此,我正在使用QNetworkAccessManager(当然还有NetworkReply和Request)进行一些下载。我可以让它在完全没有线程化的情况下完全正常工作,并阻塞应用程序,但是无论我尝试使用什么方法以非阻塞方式运行它,它都不会工作 似乎调用了NetworkAccessManager中的.get(),但要么从未连接,要么从未发送信号进行任何写入 如果您想知道为什么代码的某些部分是这样设置的,那么这是为了更容易地进行更改以尝试一系列不同的方法 我在书中读到的一件事是,尝试在一些信号发

因此,我正在使用
QNetworkAccessManager
(当然还有
NetworkReply
Request
)进行一些下载。我可以让它在完全没有线程化的情况下完全正常工作,并阻塞应用程序,但是无论我尝试使用什么方法以非阻塞方式运行它,它都不会工作

似乎调用了
NetworkAccessManager
中的
.get()
,但要么从未连接,要么从未发送信号进行任何写入

如果您想知道为什么代码的某些部分是这样设置的,那么这是为了更容易地进行更改以尝试一系列不同的方法

我在书中读到的一件事是,尝试在一些信号发射上使用
QtCore.QTimer.singleShot(0,CALL)
,将控制发送回主事件循环-尽管我尝试了,但没有任何效果

from PyQt4 import QtNetwork, QtCore, QtGui
import sys
import os


class Downloader(QtNetwork.QNetworkAccessManager):
    def __init__(self, url, dest):
        super(Downloader, self).__init__(None)

        self.get_path = url
        self.url = QtCore.QUrl(url)
        self.download_buffer = QtCore.QByteArray()

        self.dest = self.set_up_destination(dest)

        # self.request = QtNetwork.QNetworkRequest(self.url)
        # self.reply = self.get(self.request)
        #
        # self.reply.readyRead.connect(self.read_data)

        self.finished.connect(self.write_finished)
        print 'Downloader Inited'

    def startDownload(self):
        self.request = QtNetwork.QNetworkRequest(self.url)
        self.reply = self.get(self.request)

        self.reply.readyRead.connect(self.read_data)

    def set_up_destination(self, dest):
        if '.' in dest:
            dir_dest = os.path.dirname(dest)
            if not os.path.isdir(dir_dest):
                os.makedirs(dir_dest)
            return dest
        else:
            if not os.path.isdir(dest):
                os.makedirs(dest)
            base = os.path.basename(self.get_path)
            return os.path.join(dest, base).replace('\\', '/')

    def write_finished(self):
        write_file = QtCore.QFile(self.dest)
        if write_file.open(QtCore.QIODevice.WriteOnly):
            write_file.write(self.download_buffer)
            write_file.close()
            print 'Wrote File: {0}'.format(os.path.basename(self.dest))
        else:
            print 'ERROR'

    def read_data(self):
        self.download_buffer += self.reply.readAll()

    def print_progress(self, gotten, total):
        gotten = gotten/float(1000000)
        total = total/float(1000000)

        self.total = total
        divisor = total/5.0
        if gotten > (divisor*self.notify_count):
            self.notify_count += 1
            print 'Downloaded {0}/{1} Mb'.format(gotten, total)
        else:
            pass


class DownloadForm(QtGui.QDialog):
    def __init__(self, from_dir, to_dir):
        super(DownloadForm, self).__init__(None)

        self.from_dir = from_dir
        self.to_dir = to_dir

        self.downloaders = []

        self.run_count = 0
        self.done_count = 0
        self.display_label = QtGui.QLabel('Downloading items...')

        self.vlayout = QtGui.QVBoxLayout()
        self.vlayout.addWidget(self.display_label)
        self.setLayout(self.vlayout)

        self.start_downloads(self.from_dir, self.to_dir)

    def start_downloads(self, from_dir, to_dir):
        items = os.path.listdir(from_dir)
        items = [os.path.join(from_dir, x) for x in items]


        self.run_count = len(items)
        self.display_label.setText('Downloading {0} items...'.format(self.run_count))

        for item in items:
            print 'starting item: {0}'.format(os.path.basename(from_dir))
            m = Downloader(item, to_dir)
            m.finished.connect(self.adjust_run_count)
            self.downloaders.append(m)

        for item in self.downloaders:
            item.startDownload()

    @QtCore.pyqtSlot(object)
    def adjust_run_count(self, v):
        self.done_count += 1
        if self.done_count >= self.run_count:
            self.display_label.setText('All Items Finished!')


class Thread(QtCore.QThread):
    def __init__(self, lst):
        super(Thread, self).__init__(None)

        self.lst = lst

    def run(self):
        for item in self.lst:
            item.startDownload()


if __name__ == '__main__':
    app = QtGui.QApplication([])
    DIR1 = None #Give it a path to a folder containing some files
    DIR2 = None #Give it a path to an empty folder to 'copy' to.
    form = DownloadForm('DIR1',
                        'DIR2')
    form.show()
    app.exec_()
现在它被设置为在本地运行,只是为了让它工作

这是我最近的一次尝试(我想这是行不通的,但前几天我在某处看到了一篇类似的帖子,所以我想在来这里之前我会用尽一切资源——这篇文章真的很糟糕!!!)

我尝试过以下方法: 创建了一个线程(作为GUI的子线程),该线程实际生成了每个管理器对象,存储了一个变量,该变量取决于它生成了多少个管理器(例如,50个)将其完成信号连接到自己的插槽,该插槽将增加一个
finished_count
var,直到达到50(意味着它们都完成了),然后该线程将发出自己的信号,或打印“完成”或其他内容

以类似的信号/插槽方式为每个作业制作单独的线程

大家都明白了,我还尝试了其他几种方法——它们都有共同点: -涉及的
QThreads
-要么A)不工作,要么B(更有可能)工作,我做错了

我在这里有点不知所措。 希望有人能帮忙