【问题标题】:Python zipfile threading for use with progress bar用于进度条的 Python zipfile 线程
【发布时间】:2010-12-05 02:11:19
【问题描述】:

我发现自己最近越来越喜欢 SO。在尝试学习 Python(通过直接进入并尝试从 C# 移植应用程序)时,我遇到了以前从未听说过的东西:线程。当我认为我有一个基本的了解时,我尝试转换程序中压缩一个充满文件(和子目录)的目录的部分。到目前为止,这是我想出的——在一些来源的帮助下,我将在最后列出:

from Queue import Queue

import os
import gtk
import threading
import time
import zipfile

debug = True

class ProduceToQueue( threading.Thread ):
    def __init__( self, threadName, queue, window, maximum, zipobj, dirPath ):
        threading.Thread.__init__( self, name = threadName )
        self.sharedObject = queue
        self.maximum = maximum
        self.zip = zipobj
        self.dirPath = dirPath
        self.window = window

        global debug

        if debug:
            print self.getName(), "got all params."

    def run( self ):
        if debug:
            print "Beginning zip."
        files = 0
        parentDir, dirToZip = os.path.split(self.dirPath)
        includeDirInZip = False
        #Little nested function to prepare the proper archive path
        def trimPath(path):
            archivePath = path.replace(parentDir, "", 1)
            if parentDir:
                archivePath = archivePath.replace(os.path.sep, "", 1)
            if not includeDirInZip:
                archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1)
            return os.path.normcase(archivePath)
        for (archiveDirPath, dirNames, fileNames) in os.walk(self.dirPath):
            #if debug:
                #print "Walking path..."
            for fileName in fileNames:
                time.sleep( 0.001 )
                #if debug:
                    #print "After a small sleep, I'll start zipping."
                filePath = os.path.join(archiveDirPath, fileName)
                self.zip.write(filePath, trimPath(filePath))
                #if debug:
                    #print "File zipped - ",
                files = files + 1
                #if debug:
                    #print "I now have ", files, " files in the zip."
                self.sharedObject.put( files )
            #Make sure we get empty directories as well
            if not fileNames and not dirNames:
                zipInfo = zipfile.ZipInfo(trimPath(archiveDirPath) + "/")
                #some web sites suggest doing
                #zipInfo.external_attr = 16
                #or
                #zipInfo.external_attr = 48
                #Here to allow for inserting an empty directory.  Still TBD/TODO.
                outFile.writestr(zipInfo, "")

class ConsumeFromQueue( threading.Thread ):
    def __init__( self, threadName, queue, window, maximum ):
        threading.Thread.__init__( self, name = threadName )
        self.sharedObject = queue
        self.maximum = maximum
        self.window = window

        global debug

        if debug:
            print self.getName(), "got all params."

    def run( self ):
        print "Beginning progress bar update."
        for i in range( self.maximum ):
            time.sleep( 0.001 )
            #if debug:
                #print "After a small sleep, I'll get cracking on those numbers."
            current = self.sharedObject.get()
            fraction = current / float(self.maximum)
            self.window.progress_bar.set_fraction(fraction)
            #if debug:
                #print "Progress bar updated."

class MainWindow(gtk.Window):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.connect("destroy", gtk.main_quit)
        vb = gtk.VBox()
        self.add(vb)
        self.progress_bar = gtk.ProgressBar()
        vb.pack_start(self.progress_bar)
        b = gtk.Button(stock=gtk.STOCK_OK)
        vb.pack_start(b)
        b.connect('clicked', self.on_button_clicked)
        b2 = gtk.Button(stock=gtk.STOCK_CLOSE)
        vb.pack_start(b2)
        b2.connect('clicked', self.on_close_clicked)
        self.show_all()

        global debug

    def on_button_clicked(self, button):
        folder_to_zip = "/home/user/folder/with/lotsoffiles"
        file_count = sum((len(f) + len(d) for _, d, f in os.walk(folder_to_zip)))
        outFile = zipfile.ZipFile("/home/user/multithreadziptest.zip", "w", compression=zipfile.ZIP_DEFLATED)

        queue = Queue()

        producer = ProduceToQueue("Zipper", queue, self, file_count, outFile, folder_to_zip)
        consumer = ConsumeFromQueue("ProgressBar", queue, self, file_count)

        producer.start()
        consumer.start()

        producer.join()
        consumer.join()

        outFile.close()

        if debug:
            print "Done!"

    def on_close_clicked(self, widget):
        gtk.main_quit()

w = MainWindow()
gtk.main()

这个问题是在大约 7,000 个文件之后程序锁定,我必须强制退出它。我没有尝试过比这更少的文件,但我认为它可能会有同样的问题。此外,进度条不会更新。我知道它很混乱(编程风格上混合了下划线和 CamelCase,以及一般的noobish 错误),但我想不出有什么理由让它不起作用。

这是我得到最多的地方:

http://www.java2s.com/Code/Python/File/Multithreadingzipfile.htm http://www.java2s.com/Tutorial/Python/0340__Thread/Multiplethreadsproducingconsumingvalues.htm

【问题讨论】:

    标签: python multithreading progress-bar


    【解决方案1】:

    我猜file_count 是错误的,消费者永远等待.get 的另一个对象。将行更改为current = self.sharedObject.get(timeout=5),如果是这种情况,它应该在最后抛出错误。

    另外,是的,您的代码存在许多问题——例如,当您使用 GTK 时,您根本不想要自己的线程。

    GTK 有它自己的线程库,可以安全地与 gtks 主循环一起使用。请参阅 http://www.pardon-sleeuwaegen.be/antoon/python/page0.html 或 google 之类的页面了解“gtk threading”

    【讨论】:

    • >for example when you use GTK you don't want your own threads at all. 这是什么意思?我在 GTK 线程中看到的所有其他教程都是这样的。
    • 谢谢,我看看是不是搞不定。
    猜你喜欢
    • 1970-01-01
    • 2014-01-06
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多