python - 如何使用 python 以编程方式计算存档中的文件数

标签 python python-2.7 subprocess popen 7zip

在我维护的程序中,它是这样完成的:

# count the files in the archive
length = 0
command = ur'"%s" l -slt "%s"' % (u'path/to/7z.exe', srcFile)
ins, err = Popen(command, stdout=PIPE, stdin=PIPE,
                 startupinfo=startupinfo).communicate()
ins = StringIO.StringIO(ins)
for line in ins: length += 1
ins.close()
  1. 这真的是唯一的方法吗?我似乎找不到 any other command但是我不能只询问文件的数量似乎有点奇怪
  2. 错误检查呢?将其修改为:

    proc = Popen(command, stdout=PIPE, stdin=PIPE,
                 startupinfo=startupinfo)
    out = proc.stdout
    # ... count
    returncode = proc.wait()
    if returncode:
        raise Exception(u'Failed reading number of files from ' + srcFile)
    

    或者我应该实际解析 Popen 的输出?

编辑:对 7z、rar、zip 文件(由 7z.exe 支持)感兴趣——但 7z 和 zip 对初学者来说就足够了

最佳答案

用 Python 计算 zip 存档中的存档成员数:

#!/usr/bin/env python
import sys
from contextlib import closing
from zipfile import ZipFile

with closing(ZipFile(sys.argv[1])) as archive:
    count = len(archive.infolist())
print(count)

它可能使用zlib , bz2 , lzma模块(如果可用)解压缩存档。


计算 tar 压缩包中常规文件的数量:

#!/usr/bin/env python
import sys
import tarfile

with tarfile.open(sys.argv[1]) as archive:
    count = sum(1 for member in archive if member.isreg())
print(count)

可能支持gzip , bz2lzma压缩取决于 Python 版本。

您可以找到为 7z 存档提供类似功能的第 3 方模块。


使用 7z 获取存档中的文件数效用:

import os
import subprocess

def count_files_7z(archive):
    s = subprocess.check_output(["7z", "l", archive], env=dict(os.environ, LC_ALL="C"))
    return int(re.search(br'(\d+)\s+files,\s+\d+\s+folders$', s).group(1))

如果存档中有很多文件,这里的版本可能会使用更少的内存:

import os
import re
from subprocess import Popen, PIPE, CalledProcessError

def count_files_7z(archive):
    command = ["7z", "l", archive]
    p = Popen(command, stdout=PIPE, bufsize=1, env=dict(os.environ, LC_ALL="C"))
    with p.stdout:
        for line in p.stdout:
            if line.startswith(b'Error:'): # found error
                error = line + b"".join(p.stdout)
                raise CalledProcessError(p.wait(), command, error)
    returncode = p.wait()
    assert returncode == 0
    return int(re.search(br'(\d+)\s+files,\s+\d+\s+folders', line).group(1))

例子:

import sys

try:
    print(count_files_7z(sys.argv[1]))
except CalledProcessError as e:
    getattr(sys.stderr, 'buffer', sys.stderr).write(e.output)
    sys.exit(e.returncode)

计算通用子流程输出中的行数:

from functools import partial
from subprocess import Popen, PIPE, CalledProcessError

p = Popen(command, stdout=PIPE, bufsize=-1)
with p.stdout:
    read_chunk = partial(p.stdout.read, 1 << 15)
    count = sum(chunk.count(b'\n') for chunk in iter(read_chunk, b''))
if p.wait() != 0:
    raise CalledProcessError(p.returncode, command)
print(count)

它支持无限输出。


Could you explain why buffsize=-1 (as opposed to buffsize=1 in your previous answer: stackoverflow.com/a/30984882/281545)

bufsize=-1表示使用默认 I/O 缓冲区大小而不是 bufsize=0 (无缓冲)在 Python 2 上。它是 Python 2 上的性能提升。它是最近 Python 3 版本的默认设置。如果在 bufsize 的某些早期 Python 3 版本上,您可能会得到简短的读取(丢失数据)未更改为 bufsize=-1 .

这个答案以 block 的形式读取,因此流被完全缓冲以提高效率。 The solution you've linked是面向行的。 bufsize=1意思是“行缓冲”。与 bufsize=-1 的差别很小否则。

and also what the read_chunk = partial(p.stdout.read, 1 << 15) buys us ?

相当于read_chunk = lambda: p.stdout.read(1<<15)但总体上提供了更多的内省(introspection)。它用于implement wc -l in Python efficiently .

关于python - 如何使用 python 以编程方式计算存档中的文件数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31124670/

相关文章:

python - 如何查找以 {{ 开头并以 } 结尾的字符串中的所有子字符串

python - python 中的正则表达式。输出不正确

python-2.7 - tkinter canvas create_arc 方法给出圆边弧

python - PDB 中的自动完成和制表键

python - 测量外部程序的用户+系统运行时间

python - 使 tkinter 标签按设定的时间间隔刷新,无需输入

python - 如何使用 CodeHS 8.4.13 : Owls, 第 2 部分的枚举函数?

python - 如何使用 chainer 在 google colab 上从 CPU 切换到 GPU?

python-2.7 - Keras 卷积形状的尺寸无序(检查模型输入时出错)

python - Popen 包含需要对所有输出说是的命令