Python QtNetwork - 下载文件

时间:2015-05-12 00:29:40

标签: python download pyqt4 qthread qtnetwork

所以即时使用QNetworkAccessManager(当然还有NetworkReply和Request)进行一些下载。当它没有线程时我可以完全正常工作 - 并且阻止应用程序,但无论我尝试使用什么方法来使它以非阻塞方式运行,它都不会工作。

似乎来自NetworkAccessManager的.get()被调用,但要么从不连接,要么从不发送信号进行任何写作。

如果您想知道为什么代码的某些部分按照它们的方式设置,那就是允许更容易地改变以尝试一堆不同的方法。

我在SO上读到的一件事是尝试在某些信号发出时使用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_()

它的设置目前只在本地运行才能使其正常工作。

这是我最近的尝试(我觉得无法工作,但是前几天我在某个地方看到了一个与此类似的帖子所以我想在来到这里之前耗尽任何资源 - 这个真的很糟糕!!!)

我尝试过以下的事情: 创建了一个实际创建每个Manager对象的线程(作为GUI的子级),存储了一个var,它有多少管理器(例如,50)将其完成信号连接到它自己的插槽,这将增加'finished_count'var直到它达到50(meainign他们都已完成),然后发出自己的信号,或打印'完成'或其他东西。

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

你们都明白了,我尝试过其他一些方法 - 他们都有共同点: - 参与QThreads - A)不工作,或B(更有可能)工作,我做错了。

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

0 个答案:

没有答案