2014-11-02 132 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,) 
相关问题