Python QtNetwork下载文件线程化

2024-04-25 23:36:07 发布

您现在位置:Python中文网/ 问答频道 /正文

所以我用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的一个子线程),它实际创建了每个Manager对象,存储了一个var,关于它所生成的管理器(例如,50)将它们的finish signal连接到它自己的插槽,这个插槽将增加一个“finished”的var,直到它达到50(表示它们都完成了),然后它将发出自己的信号,或者打印“done”或其他东西。在

以微笑的信号/插槽方式为每个作业创建单独的线程

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

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


Tags: topathrunfromselfifosdef