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

Mr_*_*s_D 14 python subprocess 7zip popen python-2.7

在我保持的程序中,它完成如下:

# 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()
Run Code Online (Sandbox Code Playgroud)
  1. 这真的是唯一的方法吗?我似乎无法找到任何其他命令,但似乎有点奇怪,我不能只询问文件的数量
  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)
    
    Run Code Online (Sandbox Code Playgroud)

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

编辑:对7z,rar,zip档案(7z.exe支持)感兴趣 - 但7z和zip对于初学者来说已经足够了

jfs*_*jfs 13

要计算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)
Run Code Online (Sandbox Code Playgroud)

它可以使用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)
Run Code Online (Sandbox Code Playgroud)

它可以支持gzip,bz2并且lzma压缩依赖于Python版本.

您可以找到为7z档案提供类似功能的第三方模块.


要使用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))
Run Code Online (Sandbox Code Playgroud)

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

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))
Run Code Online (Sandbox Code Playgroud)

例:

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)
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

它支持无限输出.


你能解释一下为什么buffsize = -1(而不是你之前的答案中的buffsize = 1:stackoverflow.com/a/30984882/281545)

bufsize=-1意味着bufsize=0在Python 2上使用默认的I/O缓冲区大小而不是 (unbuffered).这是Python 2的性能提升.它是最近的Python 3版本的默认值.如果在某些早期的Python 3版本中bufsize没有更改,那么您可能会得到一个简短的读取(丢失数据)bufsize=-1.

这个答案以块的形式读取,因此流被完全缓冲以提高效率.您链接的解决方案 是面向行的.bufsize=1意思是"行缓冲".与bufsize=-1其他方面的差别很小.

以及read_chunk = partial(p.stdout.read,1 << 15)买了什么?

它相当于read_chunk = lambda: p.stdout.read(1<<15)但总体上提供了更多的内省.它用于在Python中有效实现wc -l.