Python Popen.communicate( )。类型错误:需要字符串或缓冲区,而不是列表

问题描述 投票:0回答:3

背景

代码应该获取一个文件对象并使用 awk 从中提取信息。

它使用 readlines() 和 'pieceSize' 作为参数。 “pieceSize”是我希望 readlines() 在遍历文件时使用的 MB 数。我这样做是希望如果需要读取的文件比我的计算机内存大得多,我的程序不会遇到麻烦。 正在读取的文件有很多行和列。

下面的代码尝试使用 awk 从第一行读取第一个字段。

import os
from subprocess import Popen, PIPE, STDOUT

def extract_info(file_object):
    pieceSize = 16777216 # 16MB
    for line in file_object.readlines(pieceSize):
        eachline = line.rsplit() # removing extra returns
        p = Popen(['awk','{{print `$`1}}'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
        pOut = p.communicate(input=eachline)[0]  
        print(pOut.decode())

错误信息

我收到的错误内容类似于...

... in _communicate_with_poll(self, input)
chunk = input[input_offset : input_offset + _PIPE_BUF]
try:
-> input_offset += os.write(fd, chunk)
except OSError as e:
if e.errno == errno.EPIPE:
TypeError: must be string or buffer, not list
python awk subprocess popen
3个回答
1
投票

发生错误是因为

str.rsplit()
返回一个 list,但
Popen.communicate()
需要一个字符串(或缓冲区)。所以你不能将
eachline
的结果传递给
communicate()

这就是问题的原因,但我不确定你为什么要分开线路。

rsplit()
将在 all 空白上拆分,包括空格、制表符等。这真的是您想要的吗?

此外,此代码将迭代

readlines()
返回的第一组行。文件的其余部分仍未处理。您需要一个外部循环来保持运行,直到输入文件耗尽(可能在调用代码中您没有显示?)。然后每行输入都会调用
Popen
一次,这将是非常低效的。

我建议你完全用Python来处理。

line.split()[0]
有效地为您提供所需的数据(文件的第一列),而无需将其传递给 awk。逐行迭代可以节省内存。

也许发电机是更好的解决方案:

def extract_info(file_object):
    for line in file_object:
        yield line.split()[0]

然后你可以在调用代码中迭代它:

with open('inputfile') as f:
    for first_field in extract_info(f):
        print first_field

0
投票

您需要将 split 返回的列表中的字符串传递给输入:

 pOut, _ = p.communicate(input=eachline[0])

您正在传递

line.rsplit()
即一个列表,不确定您到底想传递什么,也许您想要
input=" ".join(eachline)
但无论它是什么,它应该是一个字符串,而不是您传递给输入的列表本身。另外你的 awk 语法似乎不正确。

您还可以迭代文件对象本身以逐行进行,完全避免读取行。

for line in file_object:  

所以整个代码会是这样的:

def extract_info(file_object):
    for line in file_object:
        eachline = line.rsplit() # removing extra returns
        p = Popen(['awk','{print $1}'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
        pOut,_ = p.communicate(input=" ".join(eachline))
        print(pOut.decode())

显然修复了

eachline
逻辑以执行您期望它执行的任何操作。

另一方面,根本不需要使用 awk,您可以使用 python 完成所有这些工作。

def extract_info(file_object):
    for line in file_object:
        eachline = line.split(None, 1)
        print(eachline[0])

或者更简洁地使用 map 和 python3 的扩展可迭代解包:

def extract_info(file_object):
    for i, *_ in map(str.split, file_object):
        print(i)

0
投票

尚不完全清楚您期望实现什么输出。

但是,也许这会有所帮助:

  • 如果你所做的只是打印一行中的第一个单词,为什么要使用
    awk
    ,你可以使用Python来实现。
  • 如果您想读取的文件大小大于您的内存,您可以使用
    readline
    for line in file_handler
    加载每一行,您应该避免使用
    readlines()
    read()
    加载整个文件。

试试这个:

with open('myfile.txt') as f:
    for line in f:
        first_word = line.split()[0]
© www.soinside.com 2019 - 2024. All rights reserved.