如何从文件的特定行开始阅读?

4
我有一个函数,逐行读取一个大的 .txt 文件。
作为参数,我给函数传递了应该从文件中哪一行开始读取的行索引。
首先,我使用 0 调用函数,以便它从开头开始读取。 最后,我再次调用函数并传递一个新的参数,但是当它重新进入函数时,for 循环语句中的索引仍然是之前的值 0。 :(
from __future__ import print_function
import os
import sys

file = open("file.txt").read().splitlines()

for i, line in enumerate(file):
    if file[i] == "@@@TC_FIN@@@":
        fin = i;
        #print (fin)

def AssembleTC(index):

   while index < fin:

       for index, line in enumerate(file):
           if "@@@ ID:" in line:
               print(file[index+1])
               break

       for index, line in enumerate(file):
           if file[index] == "@@@TC_FIN@@@":
               recursive = index;
               #print (recursive)
               break

       AssembleTC(recursive+1)

AssembleTC(0)

对我来说,保持当前的语句与文件[index]访问过程非常重要。我读到过可以使用file.next()之类的方法跳过行,但这并不起作用。

有没有办法跳过我想要的行数,或者从更新后的索引开始新的读取呢?Python 2.7.13 - 谢谢!


每次执行 for index, line in enumerate(file): 时会从列表 file 的开头开始枚举。 - tdelaney
1
@MatthewCole 我认为他不会损坏只读文件。 - tdelaney
@tdelaney,也许不是。但是还有很多其他好的理由不要让一个打开的文件对象闲置着,所以我认为这个建议仍然适用。 - Matthew Cole
@MatthewCole file.seek()看起来没问题,因为就像我之前解释的那样,我想要一直定位到相同东西(@@@TC_FIN@@@)的索引。 但是在我定位到它之后,我能否将找到的位置传递给FOR循环,以便他从那里开始? - Marko
@Marko:如果你查看我提供的Python2文档链接,你会发现第一个参数是“offset”...但它并没有明确说明偏移量是以字节而不是行为单位计算的,与file.read(size)期望以字节为单位的大小相同。如果你的行不是等大小的字节,你将无法计算要跳过到正确行所需的字节数。如果它们在字节上大小相等,file.seek(num_lines * line_size)将从文件开头移动到num_lines。 - Matthew Cole
显示剩余8条评论
2个回答

2

这是一个很大的文本文件,因此我认为重新考虑逐行读取它的想法是值得的。文件对象会跟踪它们在文件中的位置,因此它们可以在 for 循环内部重启以进行其他处理。生成器使用 yield 将结果传递回调用者,并且是一种封装功能的好方法。

此示例扫描文件,直到看到ID,收集行直到看到FIN,然后将数据返回给调用者。它是一个生成器,因此可以从 for 循环中调用以依次获取所有记录。

from __future__ import print_function
import os
import sys

def my_datablock_iter(fileobj):
    for line in file:
        # find ID
        if "@@@ ID:" in line:
            # build a list of lines until FIN is seen
            wanted = [line.strip()]
            for line in file:
                line = line.strip()
                if line == "@@@TC_FIN@@@":
                    break
                wanted.append(line)
            # hand block back to user
            yield wanted

with open("file.txt") as fp:
    for datablock in my_datablock_iter(fp):
        print(datablock)

0

我通过擦除已经解析过的行来实现我的想法,这个方法非常有效,但这只是我的特例,因为我不再需要任何我已经操作过的数据。

对于那些仍然需要它的人,我认为@tdelaney的代码很好用,我感谢他的回答!

以下是我的做法:

from __future__ import print_function
import os
import sys

initialCall = os.stat("test.txt").st_size

def AssembleTC(parameter):

  print("CALLED PARAMETER = " + str(parameter))
  if parameter == 0:
      sys.exit()
  else:
      file = open("test.txt").read().splitlines()
      for index, line in enumerate(file):
          if file[index] == "@@@TC_FIN@@@":
              fin = index;
              print ("FIN POSITION = " + str(fin))
              break

      check = os.stat("test.txt").st_size
      print("File size = " + str(check))

      while check > 1:
          for index, line in enumerate(file):
              if "@@@ TC NR" in line:
                  print(file[index+1])
                  break
          ok=0
          with open("test.txt","r") as textobj:
              mylist = list(textobj)
              del mylist[0:fin+1]
              ok=1

          if ok==1:    
              with open("test.txt", "w") as textobj:
                  for n in mylist:
                      textobj.write(n)

          print("OLD SIZE = " + str(check))
          check = os.stat("test.txt").st_size
          print("NEW SIZE = " + str(check) + "\n")

          AssembleTC(check)

AssembleTC(initialCall)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接