【问题标题】:How to print the percentage of zipping a file python如何打印压缩文件python的百分比
【发布时间】:2015-04-15 20:33:40
【问题描述】:

我想在压缩文件时获取文件的百分比。例如,它将打印 1%、2%、3% 等。我不知道从哪里开始。我现在该怎么做呢?我只有压缩文件的代码。

代码:

zipPath = zipfile.ZipFile("Files/Zip/" + pic + ".zip", "w")

for root, dirs, files in os.walk(filePath):
    for file in files:
        zipPath.write(os.path.join(root, file), str(pic) + "\\" + file)

print("Done")
zipPath.close()

【问题讨论】:

  • 你可能想使用进度库:pypi.python.org/pypi/progress
  • 实际上,您可以选择的库似乎很少:pypi.python.org/…
  • 由于您不知道完成后文件有多大,因此似乎很难提供有关迄今为止进度的任何有用输出(@MikkoOhtamaa 的评论是关于如何显示进度的好主意如果你知道你已经走了多远,但是,在这种情况下,你怎么知道?!)
  • 此信息并非隐藏在任何地方。只需遍历源文件两次,并在第一次迭代时计算大小的总和。
  • @Mikko:文件系统可以随时更改...虽然这是一个可行的解决方案,但如果文件出现或消失,请确保您不会崩溃或行为不端(除了不正确的进度显示)时间不对。

标签: python percentage zipfile


【解决方案1】:

不幸的是,您无法从 zipfile 模块获得每个单独文件的压缩进度,但您可以通过跟踪到目前为止已处理的字节数来了解总进度。

正如 Mikko Ohtamaa 所建议的,最简单的方法是遍历文件列表两次,首先确定文件大小,然后进行压缩。然而,正如 Kevin 提到的,目录的内容可能会在这两次传递之间发生变化,因此数字可能不准确。

下面的程序(为 Python 2.6 编写)说明了这个过程。

#!/usr/bin/env python

''' zip all the files in dirname into archive zipname

    Use only the last path component in dirname as the 
    archive directory name for all files

    Written by PM 2Ring 2015.02.15

    From http://stackoverflow.com/q/28522669/4014959
'''

import sys
import os
import zipfile


def zipdir(zipname, dirname):
    #Get total data size in bytes so we can report on progress
    total = 0
    for root, dirs, files in os.walk(dirname):
        for fname in files:
            path = os.path.join(root, fname)
            total += os.path.getsize(path)

    #Get the archive directory name
    basename = os.path.basename(dirname)

    z = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)

    #Current data byte count
    current = 0
    for root, dirs, files in os.walk(dirname):
        for fname in files:
            path = os.path.join(root, fname)
            arcname = os.path.join(basename, fname)
            percent = 100 * current / total
            print '%3d%% %s' % (percent, path)

            z.write(path, arcname)
            current += os.path.getsize(path)
    z.close()


def main():
    if len(sys.argv) < 3:
        print 'Usage: %s zipname dirname' % sys.argv[0]
        exit(1)

    zipname = sys.argv[1]
    dirname = sys.argv[2]
    zipdir(zipname, dirname)


if __name__ == '__main__':
    main()

请注意,我使用 zipfile.ZIP_DEFLATED 压缩参数打开 zip 文件;默认为zipfile.ZIP_STORED,即不执行压缩。此外,zip 文件可以处理 DOS 样式和 Unix 样式的路径分隔符,因此您不需要在存档路径名中使用反斜杠,并且正如我的代码所示,您可以使用 os.path.join() 来构造存档路径名。


顺便说一句,在您的代码中,您的内部 for 循环中有 str(pic)。通常,在循环内重新评估具有常量参数的函数有点浪费。但在这种情况下,这完全是多余的,因为从您的第一条语句来看,pic 似乎已经是一个字符串。

【讨论】:

  • 这有点类似于我通过未压缩大小然后进行计算以获得总百分比的解决方案。
【解决方案2】:

现有答案仅适用于文件级别,即如果您有一个要压缩的大文件,则在整个操作完成之前您不会看到任何进展。就我而言,我只有一个巨大的文件,我做了这样的事情:

import os
import types
import zipfile
from functools import partial

if __name__ == '__main__':
    out_file = "out.bz2"
    in_file = "/path/to/file/to/zip"

    def progress(total_size, original_write, self, buf):
        progress.bytes += len(buf)
        progress.obytes += 1024 * 8  # Hardcoded in zipfile.write
        print("{} bytes written".format(progress.bytes))
        print("{} original bytes handled".format(progress.obytes))
        print("{} % done".format(int(100 * progress.obytes / total_size)))
        return original_write(buf)
    progress.bytes = 0
    progress.obytes = 0

    with zipfile.ZipFile(out_file, 'w', compression=zipfile.ZIP_DEFLATED) as _zip:
        # Replace original write() with a wrapper to track progress
        _zip.fp.write = types.MethodType(partial(progress, os.path.getsize(in_file),
                                                 _zip.fp.write), _zip.fp)
        _zip.write(in_file)

不是最优的,因为每次调用 write() 都会处理硬编码的字节数,这可能会发生变化。

此外,该函数被非常频繁地调用,可能不应该为每次调用都更新 UI。

【讨论】:

  • "AttributeError: 'file' object attribute 'write' is read-only" 我得到了上述错误。它不喜欢我更改系统对象方法调用。
  • @JasonMcCarrell 代码对我来说仍然像上面写的那样工作,只是复制并粘贴并使用 Python 3.6 运行,只有 in_file 更改为现有文件。我猜你必须做些不同的事情?
  • 啊,我用 Python 2.7 运行它。不知道为什么我们在工作中使用这样一个过时的版本。
猜你喜欢
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
  • 2011-03-01
  • 2014-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-18
相关资源
最近更新 更多