简体   繁体   English

使用 Python 跟踪 Windows 10 上的 7zip 进度

[英]Tracking 7zip progress on Windows 10 with Python

I understand 7zip has some issue, where it masks its progress from code that tries to call it (not sure why).我知道7zip有一些问题,它从试图调用它的代码中掩盖了它的进度(不知道为什么)。

I saw here that -bsp1 flag should show the hidden progress, but still nothing in Python:我在这里看到-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)

Running the 7z command in the command line gives me a nice percentage until unpacking is done.在解包完成之前,在命令行中运行 7z 命令会给我一个不错的百分比。

In Python, I get 7z's prelude printout (Path, Type etc.) and after that just b'' until I press Ctrl-c在 Python 中,我得到 7z 的前奏打印输出(路径、类型等),之后只是b''直到我按Ctrl-c

How does 7z know I'm calling it not from the "real" terminal? 7z 怎么知道我不是从“真正的”终端调用它的? Can I somehow make it look like I am, maybe using ctypes and some windows kernel call / API?我能以某种方式让它看起来像我吗,也许使用ctypes和一些 windows kernel call / API?

I saw the term "pseudo terminal" mentioned in regards to this, but I'm not sure it's relevant, and if it is, Windows' ConPTY API is hidden我看到了与此相关的术语“伪终端”,但我不确定它是否相关,如果是,则隐藏了 Windows 的ConPTY API

There is no need to use pseudo-terminal .不需要使用pseudo-terminal I am working on windows 10.我正在研究 windows 10。

Get the output could be easy but it is hard to get the progress immediately if you use stdout.readline() directly.(Because it contains \r and it will put the cursor in start of the line, then 7zip use space to fill them.).But readline() use \r\n as the seperator.获取 output 可能很容易,但如果直接使用stdout.readline()很难立即获得进度。(因为它包含\r并且它会将 cursor 放在行的开头,然后7zip使用空格填充它们.).但是readline()使用\r\n作为分隔符。

In my example, I use stdout.read(1) to get the output directly.在我的示例中,我使用stdout.read(1)直接获取 output。 Due to the progress line is 12.So I use a number to check it.由于进度线是12.所以我用一个数字来检查它。

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

This give me:这给我: 在此处输入图像描述


You could improve it:你可以改进它:

The condition of end .In my code, I used if char == b"E" .I don't think it is good.Also if you remove the .decode("gbk") in each print line, you will see the file name and the number,like: end的条件。在我的代码中,我使用了if char == b"E" 。我认为这不是很好。另外,如果你在每个打印行中删除.decode("gbk") ,你会看到文件名和编号,如:

在此处输入图像描述

Though the char split is different from the cmd(Normally it should be x% xx - filename )So there is one line delay:虽然 char split 与 cmd 不同(通常应该是x% xx - filename )所以有一行延迟:

在此处输入图像描述

I am a bit late for this question, but I have searched for an answer like jizhihaoSAMA for the last 3 days I was searching this problem.我问这个问题有点晚了,但在过去的三天里,我一直在寻找像jizhihaoSAMA这样的答案,我一直在寻找这个问题。 It is a great answer and I just wanted to share a simpler one that I manage to produce.这是一个很好的答案,我只是想分享一个我设法制作的更简单的答案。

So to print all the lines that 7zip produces this simple script is enough:因此,要打印7zip生成的所有行,这个简单的脚本就足够了:

    from subprocess import Popen, PIPE
    
    cmd = [r'C:\Program Files\7-Zip\7z.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)

But then maybe you don't want to see the blank lines that 7zip output produces.但是你可能不想看到7zip output 产生的空行。 In this case you have this possible code (the first three lines are always the same):在这种情况下,您有以下可能的代码(前三行始终相同):

    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="")

And now because you like the the original way 7zip output looks in cmd where it prints in the same line you can use this code:现在,因为您喜欢 7zip output 在 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="")

The code probably can be improved but I am also no expert in python. This is my first answer so if anything is wrong just let me know:)代码可能可以改进,但我也不是 python 方面的专家。这是我的第一个答案,所以如果有任何问题,请告诉我:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM