0

语境

该代码应该使用 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
4

3 回答 3

1

发生错误是因为str.rsplit()返回一个list,但Popen.communicate()需要一个字符串(或缓冲区)。所以你不能传递eachlineto的结果communicate()

这就是问题的原因,但我不确定你为什么要拆分线路。rsplit()将拆分所有空格,包括空格、制表符等。这真的是你想要的吗?

此外,此代码将遍历返回的第一组行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
于 2016-03-03T10:24:05.513 回答
0

目前尚不完全清楚您期望实现的输出。

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

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

尝试这个:

with open('myfile.txt') as f:
    for line in f:
        first_word = line.split()[0]
于 2016-03-03T10:40:40.917 回答
0

您需要在从拆分返回的列表中传递一个字符串到输入:

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

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

您还可以遍历文件对象本身以逐行完全避免 readlines。

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)
于 2016-03-03T10:23:38.383 回答