代码之家  ›  专栏  ›  技术社区  ›  Sam

将文件压缩成扭曲的,不阻塞。

  •  1
  • Sam  · 技术社区  · 6 年前

    有没有一种方法可以压缩文件而不阻塞Twisted?

    import zipfile
    from twisted.internet import defer
    from twisted.internet import reactor
    
    def zip_files(file_list, path, output_Zip):
        zip_handle = zipfile.ZipFile(output_zip,  mode='w', allowZip64=True)
        try:
            for i in file_list:
                zip_handle.write(i)
            zip_handle.close()
            return True
        except Exception as e:
            return False
    def print_zip(res):
        print res
        return res
    
    
    file_list = ['path_to_file1','path_to_file2']
    output_path = 'full_path_to_output_zip'
    d = defer.Deferred()
    d.addCallback(lambda _: zip_files(file_list, output_path)
    d.addCallback(print_zip)
    zip_result = d
    reactor.run()
    

    我有这个。当它工作时,触发压缩过程会导致扭曲阻塞,并等待初始的“压缩作业”完成。而是终止现有的“zip作业”并启动新的“zip作业”。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Jack Robison    6 年前

    可能是这样的,使用 DeferredList 属于 deferToThread s不阻止写入zip文件:

    import zipfile
    import logging
    from twisted.internet import threads, defer
    from twisted.internet import reactor
    
    log = logging.getLogger()
    log.addHandler(logging.StreamHandler())
    log.setLevel(logging.INFO)
    
    
    def zip_file(input_path, output_path):
        with zipfile.ZipFile(output_path,  mode='w', allowZip64=True) as zip_handle:
            zip_handle.write(input_path)
    
    
    def log_failure(err):
        log.exception("error: %s", err)
    
    
    def zip_file_and_catch_error(input_path, output_path):
        d = threads.deferToThread(zip_file, input_path, output_path)
        d.addErrback(log_failure)
        return d
    
    
    def main():
        input_paths = ['path_to_file1','path_to_file2']
        output_paths = ['path_out1','path_out2']
        assert len(input_paths) == len(output_paths)
        dl = defer.DeferredList([zip_file_and_catch_error(input_path, output_path) 
                                 for input_path, output_path in zip(input_paths, output_paths)])
        dl.addCallback(lambda result: log.info("result: %s", result))
        dl.addBoth(lambda _: reactor.callLater(0, reactor.stop))
        reactor.run()
    
    
    if __name__ == "__main__":
        main()
    
        2
  •  0
  •   notorious.no    6 年前
    import zipfile
    from twisted.internet import defer, reactor
    
    def main():
        file_list = ['path_to_file1','path_to_file2']
        output_path = 'full_path_to_output.zip'
        zip_obj = zipfile.ZipFile(output_path, mode='w', allowZip64=True)
    
        d = zip_files(zip_obj, file_list)
        d.addCallback(handle_success)
        d.addErrback(handle_error)
        d.addBoth(close_zip_obj, zip_obj = zip_obj)
    
    @defer.inlineCallbacks
    def zip_files(zip_obj, file_list):
        for item in file_list:
            yield zip_obj.write(item)
            # handle "interrupts" here
    
    def handle_success(ignore):
        print('Done zipping')
    
    def handle_error(failure):
        print('Error: {0}'.format(failure.value))
    
    def close_zip_obj(ignore, zip_obj):
        print('Closing zip object')
        zip_obj.close()
    
    main()
    reactor.run()
    

    我尽量让我的例子保持简单,这样新来的人就不会感到困惑。这个 ZipFile 对象在外部创建并传递到 zip_files() (现在装饰有 @inlineCallbacks 并返回一个“延迟的”),这样在必要时可以很容易地访问它。处理成功和错误回调(通过 addCallback/addErrback )更新这些功能以满足您的需求。最后, 压缩文件 对象,它被传递到 close_zip_obj() 在主功能中,在压缩完成后关闭。这应该可以相当快地处理大量中等大小的文件。对于大文件,您 “应该” 可以在中执行任务 deferToThread 使用原始代码。

    但是,您的评论非常含糊:

    而是终止现有的“zip作业”并启动新的“zip作业”。

    这假设如果您正处于一个压缩区的中间,您希望停止当前的压缩区并启动另一个压缩区。用 推迟三次 或者任何线程方法,在线程之间传递标志、设置/取消设置锁以及与其他线程同步都会变得单调乏味。如果您决定使用线程,请记住这一点。