2016-03-03 101 views
0

背景Python Popen.communicate()。類型錯誤:預期字符串或緩衝區,而不是列出

的代碼應該得到一個文件對象,並用awk從中提取信息。

它使用帶'pieceSize'作爲參數的readlines()。 '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 
+0

由於錯誤提示,'eachline'是'list'。你應該在'p.communicate'中傳遞'string'或'buffer'到'input'。 – Forge

+0

你期待你的程序輸出是什麼?你爲什麼使用'awk'? – Forge

回答

0

你需要傳遞一個字符串中的列表從split返回到輸入:

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

您正在通過line.rsplit()即a列表,不知道你想傳遞什麼,也許你想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]) 

甚至更​​簡潔地圖和擴展迭代拆包python3:發生

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

的錯誤,因爲str.rsplit()返回一個列表,但Popen.communicate()需要一個字符串(或緩衝液)。所以你不能將eachline的結果傳遞給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 
0

這不是完全清楚你期待什麼樣的輸出來實現。

但是,也許這將是有益的:

  • 爲什麼要用awk如果你正在做的是在打印行的第一個字,你可以用Python這一點。
  • 如果要讀取大小超過內存大小的文件,可以使用readlinefor line in file_handler加載每行,您應該避免使用加載整個文件的readlines()read()

試試這個:

with open('myfile.txt') as f: 
    for line in f: 
     first_word = line.split()[0] 
相關問題