2010-12-03 76 views
2

如何從文件中讀取n行而不是隻讀一行?我有一個有明確定義結構的文件,我願做這樣的事情:從Python中的文件(但不是全部)讀取n行

for line1, line2, line3 in file: 
    do_something(line1) 
    do_something_different(line2) 
    do_something_else(line3) 

,但它不工作:

ValueError: too many values to unpack

現在我這樣做:

for line in file: 
    do_someting(line) 
    newline = file.readline() 
    do_something_else(newline) 
    newline = file.readline() 
    do_something_different(newline) 
... etc. 

這很糟糕,因爲我正在編寫無休止的'newline = file.readline()'這是混亂的代碼。 有沒有什麼聰明的方法來做到這一點? (我真的想避免一次讀取整個文件,因爲它很大)

+0

與downvote什麼? – Yehonatan 2010-12-03 11:53:37

+0

`file`是Python中的一個迭代器,請參閱http:// stackoverflow。/ 434287 /什麼是最蟒蛇式的方式來重複在列表塊/ 434411#434411 – jfs 2010-12-04 15:34:02

回答

4

基本上,你的file是一個迭代器,它一次產生一行文件。這將您的問題變成了如何從迭代器中一次產生多個項目。該解決方案在this question中給出。請注意,函數islice位於itertools模塊中,因此您必須從那裏導入它。

0

如果你的目的是做同樣的事情,爲什麼你需要每次迭代處理多行?

對於文件中的行是你的朋友。它通常比手動讀取文件更有效率,無論是在IO性能還是內存方面。

+0

對不起,編輯,我想做不同的事情,以每一行一批n行,然後對另一批n個文件中的行做同樣的事情 – 2010-12-03 03:06:42

1

for i in file產生str,所以你不能只是做for i, j, k in file和三個批次(試行a, b, c = 'bar'a, b, c = 'too many characters'和看的,b和c的值,以制定出爲什麼你的「太多的閱讀值解包「)。

它不是完全清楚你的意思,但如果你正在做的每一行同樣的事情,只是想停在某個點,然後像這樣做:

for line in file_handle: 
    do_something(line) 
    if some_condition: 
     break # Don't want to read anything else 

(另外,不要不會使用file作爲變量名稱,因此您正在調整內置值。)

0

您是否知道有關數據行/格式長度的信息?如果是這樣,你可以讀取前n個字節(比如80 * 3)和f.read(240).split(「\ n」)[0:3]。

+0

不幸的是,它是巨大的xml'like文件,其中一些值可能有不同的長度 – 2010-12-03 03:05:01

+0

最大的文件有多大? 10K? 1MB? 100MB?我認爲它太大而無法讀取整個文件,但即使在100K下讀取也會便宜/快速。除非你必須在緊密的循環中進行一百萬次。 – 2010-12-03 03:10:59

+0

我現在擁有的文件是80MB,未來可能會有更大的文件;我不想將問題全部加載到內存中,因爲這個問題經常出現(至少對我來說)) – 2010-12-03 03:16:56

0

如果你想能夠一遍又一遍用這個數據,一個方法可能是這樣:

lines = [] 
for line in file_handle: 
    lines.append(line) 

這會給你的行的列表,你可以再通過訪問指數。另外,當你說一個巨大的文件時,它的大小很可能是微不足道的,因爲python可以很快處理數千行。

3

如果是xml,爲什麼不使用lxml?

0

爲什麼你就不能這樣做:

CTR = 0

在文件行:

if ctr == 0: 

    .... 

    elif ctr == 1: 

    .... 

    ctr = ctr + 1 

如果你發現如果/ elif的構建醜,你可以只創建哈希表或函數指針列表,然後執行:

對於文件中的行:

function_list[ctr]() 

或類似

2

你可以使用一個輔助函數是這樣的:

def readnlines(f, n): 
    lines = [] 
    for x in range(0, n): 
     lines.append(f.readline()) 
    return lines 

然後,像你想你可以做一些事情:

while True: 
    line1, line2, line3 = readnlines(file, 3) 
    do_stuff(line1) 
    do_stuff(line2) 
    do_stuff(line3) 

話雖這麼說,如果你是使用xml文件,如果使用真正的xml解析器,您可能會長期得到更高興...

0

這聽起來像你試圖從磁盤並行讀取......這是很難做到的。所有給你的解決方案都是現實和合法的。你不應該因爲代碼「看起來很醜陋」而讓某些東西讓你失望。最重要的是它的效率/效果如何,那麼如果代碼很混亂,你可以整理它,但不要尋找一種全新的方法來做某件事,因爲你不喜歡這樣做的一種方式看起來像在代碼中。

至於內存不足,您可能需要退房pickle

0

這可以通過巧妙使用zip函數來實現。它很短,但是對於我的口味有點巫術(很難看出它是如何工作的)。它會切斷最後沒有填滿組的所有行,這可能是好的或壞的,取決於你在做什麼。如果你需要最後的線路,itertools.izip_longest可能會訣竅。

zip(*[iter(inputfile)] * 3) 

更明確地,靈活地做,這是墊埃克伯格的解決方案的修改:

def groupsoflines(f, n): 
    while True: 
     group = [] 
     for i in range(n): 
      try: 
       group.append(next(f)) 
      except StopIteration: 
       if group: 
        tofill = n - len(group) 
        yield group + [None] * tofill 
       return 
     yield group 

for line1, line2, line3 in groupsoflines(inputfile, 3): 
    ... 

注:如果在一個組的中途沒有線路,它將填補None的空缺,以便您仍然可以將其解包。因此,如果文件中的行數可能不是3的倍數,則需要檢查line2line3是否爲None

2

itertools救援:

import itertools 
def grouper(n, iterable, fillvalue=None): 
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" 
    args = [iter(iterable)] * n 
    return itertools.izip_longest(fillvalue=fillvalue, *args) 


fobj= open(yourfile, "r") 
for line1, line2, line3 in grouper(3, fobj): 
    pass 
相關問題