【问题标题】:subprocess and Type Str doesnt support the buffer APIsubprocess 和 Type Str 不支持缓冲区 API
【发布时间】:2013-03-26 21:27:30
【问题描述】:

我有

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

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

我在 Python 3.3 上做错了什么

【问题讨论】:

    标签: python subprocess python-3.3


    【解决方案1】:

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

    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 或更高版本,则可以对 Popen() 调用使用显式的 encoding 参数来指定要使用的不同编解码器,例如 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,只需显式解码字节中的文本即可。

    您试图使用 str 参数拆分 bytes 值:

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

    【讨论】:

    • 感谢它有效,但知道为什么我的列表索引超出范围错误
    • @NickLoach:该行少于 3 列?
    • 感谢 Martijn 该行有 ['03-04-2013', '', '19:48', '', '', '', '', '', ' ', '', '', '', '', '', '', '', '.ipython\r\n'] 我想要名为 .ipython 的字段作为输出
    • 为什么不改用os.listdir()
    • 我做了一个简单的例子,我将运行的命令不是 os 命令,而是在上述行中输出某些内容的二进制文件
    【解决方案2】:

    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)
    

    【讨论】:

    • dir 是 Windows 上的内部命令,即,如果没有 dir.exe,则在这种情况下需要 shell=True
    • 如果我们假设一列输出,那么您可以使用.splitlines(),来处理带有空格的路径
    • @J.F.Sebastian,同意了。我没有使用.splitlines(),因为我的dir (GNU coreutils) 8.21 版本在多个列中产生输出。
    • 如果 stdout 被重定向,dir 会产生单列输出(stdout=PIPE 就是这种情况)。尝试dir | cat,在终端中查看
    【解决方案3】:

    最好使用binascii.b2a_uu,它将二进制数据转换为一行ASCII字符

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-06
      • 2015-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-25
      相关资源
      最近更新 更多