跟踪 Windows 10 上的 7zip 进度 Python

Tracking 7zip progress on Windows 10 with Python

我知道 7zip 有一些问题,它掩盖了试图调用它的代码的进度(不确定为什么)。

我看到 here -bsp1 标志应该显示隐藏的进度,但在 Python:

中仍然没有
from subprocess import Popen, PIPE
from time import sleep

cmd = Popen('7z.exe e D:\stuff.rar -od:\stuff -aoa -bsp1'.split(), stdout=PIPE, stderr=PIPE)

while cmd.poll() !=0:  # Not sure this helps anything
    out = cmd.stdout.read()
    print(out)
    sleep(1)

运行 命令行中的 7z 命令在解包完成之前给了我一个很好的百分比。

在 Python 中,我得到 7z 的前奏打印输出(路径、类型等),之后只是 b'',直到我按 Ctrl-c

7z 怎么知道我不是从“真实”终端调用它的?我能以某种方式让它看起来像我吗,也许使用 ctypes 和一些 windows 内核调用/API?

我看到了与此相关的术语“伪终端”,但我不确定它是否相关,如果相关,Windows' ConPTY API is hidden

不需要使用pseudo-terminal。 我正在研究 windows 10.

直接使用stdout.readline()获取输出可能很容易,但很难立即获取进度。(因为它包含\r,它会将光标放在 行的开头,然后 7zip 使用 space 来填充它们。)。但 readline() 使用 \r\n 作为分隔符。

在我的示例中,我使用stdout.read(1) 直接获取输出。 由于进度条是12.So我用一个数字来查看。

import subprocess

s = "D:/7-Zip/7z.exe e E:/work/Compile/python/python_project/temp/test.zip -oE:/work/Compile/python/python_project/temp/test -aoa -bsp1"
p = subprocess.Popen(s.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
i = 0
while True:
    line = p.stdout.readline()
    if line:
        if i == 11:
            s = b""
            while True:
                char = p.stdout.read(1)
                if char == b"E": # "Everything is ok" means end
                    break
                s += char
                if char == b"%":
                    print(s.decode("gbk"))
                    s = b""
        print(line.decode("gbk"))
        i += 1

这给我:


您可以改进它:

end的条件。在我的代码中,我使用了if char == b"E"。如果你把每个打印中的.decode("gbk")去掉,我认为它不是good.Also行,你会看到文件名和编号,如:

虽然char split和cmd不同(一般应该是x% xx - filename)所以有一行延迟:

我问这个问题有点晚了,但在过去 3 天里我一直在搜索类似 jizhihaoSAMA 的答案。这是一个很好的答案,我只是想分享一个我设法制作的更简单的答案。

所以打印 7zip 产生的所有行这个简单的脚本就足够了:

    from subprocess import Popen, PIPE
    
    cmd = [r'C:\Program Files-Zipz.exe', 'a', r'C:\ola\cenas.exe', "-sfx", r'C:\ola' + "\*", '-mmt', '-mx5', "-bsp1"]
    
    final_str = ["Files read from disk:", "Archive size", "Everything is Ok"]
    
    i = 0
    with Popen(cmd, stdout=PIPE, bufsize=1,
               universal_newlines=True) as p:
        for line in p.stdout:
            line = line.replace("\n", "")
            print(line)

但是您可能不想看到 7zip 输出产生的空行。在这种情况下,您有以下可能的代码(前三行始终相同):

    i = 0
    with Popen(cmd, stdout=PIPE, bufsize=1, universal_newlines=True) as p:
        for line in p.stdout:
            i = i + 1
            if "+" in line or i < 15 or any(s in line for s in final_str):
            
                if "Files read from disk:" in line:
                    print("\n", line)
                else:
                    print(line, end="")

现在因为您喜欢 7zip 输出在 cmd 中的原始方式,它在同一行中打印,您可以使用此代码:

    i = 0
    with Popen(cmd, stdout=PIPE, bufsize=1,
               universal_newlines=True) as p:
        for line in p.stdout:
            i = i + 1
            if "+" in line or i < 14 or any(s in line for s in final_str):
    
                if "+" in line:
                    line = line.replace("\n", "")
                    print("\r", line, end="")
                elif final_str[0] in line:
                    print("\n\n", line, end="")
                else:
                    print(line, end="")

代码可能可以改进,但我也不是 python 方面的专家。这是我的第一个回答,所以如果有任何问题请告诉我:)