subprocess和Type Str不支持缓冲区API

时间:2013-04-04 17:07:20

标签: python subprocess python-3.3

我有

cmd = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
for line in cmd.stdout:
  columns = line.split(' ')
  print (columns[3])

第3行有错误类型Str不支持缓冲区API。

我在Python 3.3上做错了什么

3 个答案:

答案 0 :(得分:20)

您正在读取二进制数据,而不是str,因此您需要先解码输出。如果您将universal_newlines参数设置为True,则使用locale.getpreferredencoding() method的结果自动解码stdout  (与打开文本文件相同):

cmd = subprocess.Popen(
    'dir', shell=True, stdout=subprocess.PIPE, universal_newlines=True)
for line in cmd.stdout:
    columns = line.decode().split()
    if columns:
        print(columns[-1])

如果使用Python 3.6或更高版本,则可以使用显式encoding参数进行Popen()调用,以指定要使用的其他编解码器,例如,UTF-8:

cmd = subprocess.Popen(
    'dir', shell=True, stdout=subprocess.PIPE, encoding='utf8')
for line in cmd.stdout:
    columns = line.split()
    if columns:
        print(columns[-1])

如果您需要在Python 3.5或更早版本中使用不同的编解码器,请不要使用universal_newlines,只需明确地从字节解码文本。

您尝试使用bytes参数分割str值:

>>> b'one two'.split(' ')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Type str doesn't support the buffer API

通过解码,您可以避免此问题,并且您的print()调用也不必在b'..'之前添加输出。

但是,您可能只想使用os模块来获取文件系统信息:

import os

for filename in os.listdir('.'):
    print(filename)

答案 1 :(得分:4)

Martijn Pieters's answer第一部分的简单解决方案是将universal_newlines=True参数传递给Popen调用。

我甚至会将其简化为:

output = subprocess.check_output('dir', universal_newlines=True)
columns = output.split()
print(columns)

注意:如果文件或目录名称包含空格,请按照Martijn Pieters's answer中的建议使用os.listdir('.')或类似以下内容:

output = subprocess.check_output('dir', universal_newlines=True)
columns = []
for e in output.split():
    if len(columns) > 0 and columns[-1].endswith('\\'):
        columns[-1] = columns[-1][:-1] + " " + e
    else:
        columns.append(e)
print(columns)

答案 2 :(得分:0)

更好地使用binascii.b2a_uu将二进制数据转换为ASCII字符行

from binascii import b2a_uu 
cmd = b2a_uu(subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE))