2014-11-02 61 views
2

我想逐行讀取文件,除了最後N行。我如何知道在Python中如何停止,而無需到達文件末尾並回溯/放棄最後N行?是要求#lines = X,並且循環(X-N)是一個很好的方法來解決這個問題?簡單的方法是不讀取Python中文件的最後N行

什麼是最簡單/最Pythonic這樣做?

+5

一般來說,如果行可以是可變長度的,那麼*沒有辦法* Pythonic或其他方法知道文件中有多少行沒有讀取。 – 2014-11-02 05:37:53

+0

你可以使用'readlines'讀取文件,然後應用'len'來獲得文件中的總行數,現在你可以做 – Hackaholic 2014-11-02 05:39:03

+1

@Hackaholic你剛剛讀過這些行......不是len,你可以切片[:-N] ...這是「丟棄最後N行」... – 2014-11-02 05:42:42

回答

2

三種不同的解決方案:

1)快速和骯髒的,看到約翰的回答是:

with open(file_name) as fid: 
    lines = fid.readlines() 
for line in lines[:-n_skip]: 
    do_something_with(line) 

這種方法的缺點是您必須首先讀取內存中的所有行,這可能是大文件的問題。

2)兩經過

進程中的文件兩次,一次用於計數線n_lines的數目,以及在第二遍中處理僅第一n_lines - n_skip行:

# first pass to count 
with open(file_name) as fid: 
    n_lines = sum(1 for line in fid) 

# second pass to actually do something 
with open(file_name) as fid: 
    for i_line in xrange(n_lines - n_skip): # does nothing if n_lines <= n_skip 
     line = fid.readline() 
     do_something_with(line) 

的缺點此方法是您必須遍歷文件兩次,在某些情況下可能會更慢。不過,好事是你內存中永遠不會有多行。

3)使用

如果你想遍歷文件只是一次緩衝,類似塞爾的解決方案,你只知道爲確保您可以處理線i,如果你知道行i + n_skip存在。這意味着您必須首先將n_skip行保存在臨時緩衝區中。要做到這一點的方法之一是實現某種形式的FIFO緩衝液(例如用一臺發電機的功能,實現循環緩衝器):

def fifo(it, n): 
    buffer = [None] * n # preallocate buffer 
    i = 0 
    full = False 
    for item in it: # leaves last n items in buffer when iterator is exhausted 
     if full: 
      yield buffer[i] # yield old item before storing new item 
     buffer[i] = item 
     i = (i + 1) % n 
     if i == 0: # wrapped around at least once 
      full = True 

快速測試了一系列數字:

In [12]: for i in fifo(range(20), 5): 
    ...:  print i, 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 

方式你將與​​你的文件中使用此:

with open(file_name) as fid: 
    for line in fifo(fid, n_skip): 
     do_something_with(line) 

注意,這需要足夠的內存來臨時存儲n_skip線,但是這仍然比讀備忘錄中的所有行更好像第一個解決方案一樣。

這三種方法中哪一種最好是在代碼複雜度,內存和速度之間取捨,這取決於您的確切應用。

1

要讀取最後X行的所有行,您需要知道最後一行X行的起始位置。你將需要這個信息。 有幾種方法可以獲取這些信息。

  1. 當你寫入文件時保存最後X行的位置。到達該位置時停止閱讀。
  2. 存儲從某處開始的行的位置,這允許附加到該文件。
  3. 你知道線的大小。
    1. 每行可以有相同的尺寸和你計算出來的文件大小
    2. 每一行都有至少一個字符,這樣你就不用看了最後X字符。
1

鑑於我們所知道的文件必須讀到尾,以確定有多少行有,這是我在閱讀了最後n線「簡單/最Python的方式」的嘗試:

with open(foo, 'r') as f: 
    lines = f.readlines()[:-n] 
+2

也許更簡單:'lines = f.readlines()[: - n]',ciao from – gboffi 2014-11-02 10:15:08

+0

當然,我不知道爲什麼我最初沒有這樣寫,累了我猜:) – 2014-11-02 10:18:59

+1

在洛杉磯,是嗎?在意大利,我們用它來祝福「晚安,夢見黃金!」 – gboffi 2014-11-02 11:17:14

2

除非你有辦法事先知道實際的行數,否則你將不得不閱讀整個文件。

但是當我想你想過程由行的文件行除了N個最後一行,你可以不用加載在內存中的所有文件,並只保留一個爲N行名單:

with open(file) as fd: 
    lines = [] 
    try: 
     for i in range(N): 
      lines.append(next(fd)) 

     i = 0 
     for line in fd: 
      # process lines[i] 
      print (lines[i].rstrip()) 
      lines[i] = line 
      i = (i + 1) % N 
    except StopIteration: 
     print "less than %d lines" % (N,) 
相關問題