Python 使用universal_newlines=True(bufsize=1)和使用Popen的默认参数有什么区别
我试图读取从Python调用的子进程的输出。为此,我使用Popen(因为我认为如果使用subprocess.call,就不可能使用管道stdout) 到目前为止,我有两种方法,在测试中,似乎提供了相同的结果。代码如下:Python 使用universal_newlines=True(bufsize=1)和使用Popen的默认参数有什么区别,python,python-3.x,subprocess,popen,Python,Python 3.x,Subprocess,Popen,我试图读取从Python调用的子进程的输出。为此,我使用Popen(因为我认为如果使用subprocess.call,就不可能使用管道stdout) 到目前为止,我有两种方法,在测试中,似乎提供了相同的结果。代码如下: with Popen(['Robocopy', source, destination, '/E', '/TEE', '/R:3', '/W:5', '/log+:log.txt'], stdout=PIPE) as Robocopy: for line in Roboc
with Popen(['Robocopy', source, destination, '/E', '/TEE', '/R:3', '/W:5', '/log+:log.txt'], stdout=PIPE) as Robocopy:
for line in Robocopy.stdout:
line = line.decode('ascii')
message_list = [item.strip(' \t\n').replace('\r', '') for item in line.split('\t') if item != '']
print(message_list[0], message_list[0])
Robocopy.wait()
returncode = Robocopy.returncode
及
第一种方法不包括universal_newlines=True,因为文档中说明了这一点
第二个版本确实包含universal_新行,因此我指定了一个bufsize
有人能给我解释一下区别吗?我找不到这篇文章,但我确实读到了缓冲区溢出导致某种问题的问题,因此在stdout中使用for line的重要性
此外,在查看输出时,不指定universal_换行符会使stdout成为bytes
对象-但我不确定如果我只是使用ascii
(新行和制表符)解码bytes对象与universal_换行符模式相比会有什么不同
最后,将bufsize
设置为1
会使输出“行缓冲”,但我不确定这意味着什么。如果能解释一下这些不同的元素是如何结合在一起的,我将不胜感激。谢谢
使用universal_newlines=True(bufsize=1)和使用Popen的默认参数有什么区别
默认值是:universal\u newlines=False
(意味着输入/输出被接受为字节,而不是Unicode字符串加上处理(因此参数的名称。Python 3.7提供了文本
别名,在这里可能更直观)被禁用——您可以按原样获取二进制数据(除非Windows上的POSIX层搞砸了)和bufsize=-1
(这意味着流被完全缓冲——使用默认缓冲区大小)
universal\u newlines=True
使用locale.getpreferredencoding(False)
字符编码来解码字节(这可能不同于代码中使用的ascii
编码)
如果universal\u newlines=False
则对Robocopy中的行执行。标准输出:
迭代b'\n'
-分隔行。如果进程使用非ascii编码(例如UTF-16)进行输出,则即使系统上的os.linesep='\n'
,也可能会得到错误的结果。如果要使用文本行,请使用文本模式:显式传递universal\u newlines=True
或使用io.TextIOWrapper(process.stdout)
第二个版本确实包含universal_新行,因此我指定了一个bufsize
通常,如果使用universal\u newlines
(可以,但不是必需的),则无需指定bufsize
。bufsize=1
启用行缓冲模式(如果要写入process.stdin
,输入缓冲区将在换行符上自动刷新)否则,它相当于默认值bufsize=-1
,因此bufsize=-1
的默认值似乎可能会导致问题。完全缓冲流可能会导致某种类型的阻塞,如果未指定(在通用\u换行模式下)同样,我不是因为缓冲区已满而创建了阻塞的可能性吗?@Startec:不是。这里没有阻塞问题(不管universal\u newlines
,bufsize
值如何)。您从哪里得到这些想法?如果您对某些特定代码有疑问,请询问有关此特定代码的问题。很抱歉,我的困惑来自子流程的文档(也就是说,不要将stdout=PIPE或stderr=PIPE与此函数一起使用。如果子进程生成足够的输出到一个管道,以填充操作系统管道缓冲区,则子进程将被阻止,因为这些管道没有被读取。)
但我现在看到这是subprocess.call。感谢您的明确回答-它解决了我的问题@Startec:是的。如果您不读取进程.stdout
管道(当stdout=pipe
时),则子进程可能会阻塞,即操作系统管道缓冲区可能是有限的(至少在某些系统上),因此,一旦子进程填充它,它将无法再写入(直到通过从管道末端读取来耗尽缓冲区)。注意:OS管道缓冲区位于父Python脚本之外;它与bufsize
(控制父Python脚本内的缓冲区)无关,
with Popen(['Robocopy', source, destination, '/E', '/TEE', '/R:3', '/W:5', '/log+:log.txt'], stdout=PIPE, universal_newlines=True, bufsize=1) as Robocopy:
for line in Robocopy.stdout:
message_list = [item.strip() for item in line.split('\t') if item != '']
print(message_list[0], message_list[2])
Robocopy.wait()
returncode = Robocopy.returncode