Windows系统Python subprocess调用7-Zip无法显示压缩进度求助
Python subprocess调用7z.exe无法显示实时压缩进度的问题
问题描述
在Windows CMD中直接执行7z.exe压缩命令时,能看到百分比形式的实时压缩进度;但通过Python的subprocess模块调用该命令时,终端无法显示该进度。测试ping 192.168.0.1命令时,控制台可实时输出结果。相关测试代码如下:
import subprocess command =r'E:\7-Zip\7z.exe a ArchiveName.7z D:\my7zip_test' command1 = r'ping 192.168.0.1' # Use subprocess.Popen to run the command and capture the output process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, universal_newlines=True) # Read and print the output while the process is running while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: print(output.strip()) # Get the return code of the process return_code = process.returncode if return_code == 0: print("Compression completed successfully.") else: print(f"Compression failed with return code {return_code}")
原因分析
- 7z的输出逻辑:7z.exe默认仅在交互式终端环境(比如直接打开的CMD窗口)下输出实时压缩进度。当通过subprocess将stdout/stderr重定向到管道时,7z会判断当前环境为非交互式,自动关闭实时进度输出,仅在压缩完成后输出最终结果。
- ping命令的差异:ping命令的输出逻辑不同,它会持续将每一行结果输出到stdout,无论当前环境是否为交互式,因此subprocess可以实时捕获并打印。
解决方法
方法一:强制7z输出进度信息
通过添加7z的-bsp1参数,强制将实时进度输出到标准输出(stdout),这样即使输出被管道捕获,也能实时获取进度信息。修改后的代码如下:
import subprocess # 添加-bsp1参数强制输出进度 command =r'E:\7-Zip\7z.exe a -bsp1 ArchiveName.7z D:\my7zip_test' process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, universal_newlines=True) while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: # 保留进度行的格式,不要strip()避免进度覆盖效果丢失 print(output, end='') return_code = process.returncode if return_code == 0: print("\nCompression completed successfully.") else: print(f"\nCompression failed with return code {return_code}")
注意:这里去掉了
strip()并使用end='',是为了保留7z进度行的覆盖式输出效果(类似CMD中进度百分比动态更新的样子)。
方法二:让子进程继承父进程的控制台
不重定向stdout/stderr,直接让7z子进程使用父进程的终端输出,这样7z会认为是交互式环境,自动输出实时进度。修改后的代码如下:
import subprocess command =r'E:\7-Zip\7z.exe a ArchiveName.7z D:\my7zip_test' # 不设置stdout/stderr参数,默认继承父进程的输出流 process = subprocess.Popen(command, shell=True) # 等待子进程完成 process.wait() return_code = process.returncode if return_code == 0: print("\nCompression completed successfully.") else: print(f"\nCompression failed with return code {return_code}")
这种方法更简单,缺点是无法在代码中捕获和处理7z的输出内容,仅能在终端直接看到进度。
内容的提问来源于stack exchange,提问作者blues
相关产品推荐
相关产品推荐

