如何从文件中读取特定行(按行号)?

Posted

技术标签:

【中文标题】如何从文件中读取特定行(按行号)?【英文标题】:How to read specific lines from a file (by line number)? 【发布时间】:2011-01-06 02:42:51 【问题描述】:

我正在使用for 循环读取文件,但我只想读取特定行,例如行#26#30。是否有任何内置功能可以实现这一点?

【问题讨论】:

可能重复:***.com/questions/620367/… 【参考方案1】:

如果要读取的文件很大,并且您不想一次读取内存中的整个文件:

fp = open("file")
for i, line in enumerate(fp):
    if i == 25:
        # 26th line
    elif i == 29:
        # 30th line
    elif i > 29:
        break
fp.close()

注意i == n-1nth 行。


在 Python 2.6 或更高版本中:

with open("file") as fp:
    for i, line in enumerate(fp):
        if i == 25:
            # 26th line
        elif i == 29:
            # 30th line
        elif i > 29:
            break

【讨论】:

+1 如果整个文件没有像linecache 那样加载到内存中,则比我的解决方案更好。你确定enumerate(fp) 没有这样做吗? enumerate(x) 使用x.next,因此它不需要内存中的整个文件。 我的小牛肉是 A) 你想用 with 而不是开/关对,因此保持身体短,B) 但身体没那么短。听起来像是速度/空间和 Pythonic 之间的权衡。我不确定最好的解决方案是什么。 with 被高估了,没有它,python 相处了 13 年以上 @Dan D. 电力被高估了,人类在没有电力的情况下相处了 20 万多年。 ;-) 'with' 让​​它更安全、更易读、更短。【参考方案2】:

快速回答:

f=open('filename')
lines=f.readlines()
print lines[25]
print lines[29]

或:

lines=[25, 29]
i=0
f=open('filename')
for line in f:
    if i in lines:
        print i
    i+=1

有一个更优雅的提取多行的解决方案:linecache(由 "python: how to jump to a particular line in a huge text file?" 提供,之前的 ***.com 问题)。

引用上面链接的python文档:

>>> import linecache
>>> linecache.getline('/etc/passwd', 4)
'sys:x:3:3:sys:/dev:/bin/sh\n'

4 更改为您想要的行号,然后就可以了。请注意,4 将带来第五行,因为计数是从零开始的。

如果文件可能非常大,并且在读入内存时会出现问题,那么使用@Alok's advice and use enumerate() 可能是个好主意。

总结:

使用fileobject.readlines()for line in fileobject 作为小文件的快速解决方案。 使用linecache 获得更优雅的解决方案,这样可以非常快速地读取多个文件,并且可能重复读取。 将@Alok's advice and use enumerate() 用于可能非常大且无法放入内存的文件。请注意,使用此方法可能会变慢,因为文件是按顺序读取的。

【讨论】:

不错。我刚刚查看了linecache 模块的来源,看起来它读取了内存中的整个文件。所以,如果随机访问比大小优化更重要,linecache 是最好的方法。 with linecache.getlin('some_file', 4) 我得到的是第 4 行,而不是第 5 行。 有趣的事实:如果在第二个示例中使用集合而不是列表,则运行时间为 O(1)。在列表中查找是 O(n)。内部集合表示为哈希,这就是您获得 O(1) 运行时间的原因。在这个例子中没什么大不了的,但是如果使用大量的数字列表,并且关心效率,那么集合是要走的路。 linecache 现在似乎只适用于 python 源文件 也可以使用linecache.getlines('/etc/passwd')[0:4]读取第一、二、三、四行。【参考方案3】:

为了提供另一种解决方案:

import linecache
linecache.getline('Sample.txt', Number_of_Line)

我希望这快速简单:)

【讨论】:

希望这是最佳解决方案。 这会将整个文件读入内存。您不妨调用 file.read().split('\n') 然后使用数组索引查找来获取感兴趣的行... 你能举个例子吗@duhaime @anon ''.join(file.readlines()).split('\n'))[5:10] 例如给你第 6 到 10 行。不推荐,因为它会将整个文件读入内存。 这是一个例子,它对我有用: def get_version(): versionLine = linecache.getline('config.php', 4) version = versionLine[19:24] return version【参考方案4】:

一种快速而紧凑的方法可能是:

def picklines(thefile, whatlines):
  return [x for i, x in enumerate(thefile) if i in whatlines]

这接受任何打开的类似文件的对象thefile(由调用者决定是否应该从磁盘文件,或者通过例如套接字或其他类似文件的流打开)和一组从零开始的行索引whatlines,并返回一个列表,内存占用少,速度合理。如果要返回的行数很大,您可能更喜欢生成器:

def yieldlines(thefile, whatlines):
  return (x for i, x in enumerate(thefile) if i in whatlines)

这基本上只适用于循环 - 请注意,唯一的区别在于在 return 语句中使用圆括号而不是方括号,分别进行列表理解和生成器表达式。

进一步注意,尽管提到了“行”和“文件”,但这些函数是很多、很多更通用的——它们可以在 any 可迭代、它是一个打开的文件或任何其他文件,根据它们的渐进项目编号返回项目列表(或生成器)。所以,我建议使用更恰当的通用名称;-)。

【讨论】:

@ephemient,我不同意——genexp 读起来流畅而完美。 优秀而优雅的解决方案,谢谢!事实上,即使是大文件也应该支持生成器表达式。没有比这更优雅的了,不是吗? :) 不错的解决方案,这与@AdamMatan 提出的解决方案相比如何? Adam 解决方案可能会更快,因为它利用了可能导致提前停止的额外信息(单调递增的行号)。我有一个 10GB 的文件,无法加载到内存中。 @Mannaggia 这个答案强调的不够,但whatlines 应该是set,因为if i in whatlines 使用集合而不是(排序的)列表将执行得更快。我没有首先注意到它,而是用排序列表设计了我自己的丑陋解决方案(我不必每次都扫描列表,而if i in whatlines 就是这样做的),但性能差异可以忽略不计(用我的数据) 并且这个解决方案更加优雅。【参考方案5】:

为了完整起见,这里还有一个选项。

让我们从python docs的定义开始:

slice 一个对象,通常包含一个序列的一部分。切片是使用下标表示法创建的,当给出多个数字时,[] 在数字之间使用冒号,例如在 variable_name[1:3:5] 中。括号(下标)表示法在内部使用切片对象(或在旧版本中,__getslice__() 和 __setslice__())。

虽然切片符号通常不能直接应用于迭代器,但itertools 包包含一个替换函数:

from itertools import islice

# print the 100th line
with open('the_file') as lines:
    for line in islice(lines, 99, 100):
        print line

# print each third line until 100
with open('the_file') as lines:
    for line in islice(lines, 0, 100, 3):
        print line

该函数的另一个优点是它直到结束才读取迭代器。所以你可以做更复杂的事情:

with open('the_file') as lines:
    # print the first 100 lines
    for line in islice(lines, 100):
        print line

    # then skip the next 5
    for line in islice(lines, 5):
        pass

    # print the rest
    for line in lines:
        print line

并回答原来的问题:

# how to read lines #26 and #30
In [365]: list(islice(xrange(1,100), 25, 30, 4))
Out[365]: [26, 30]

【讨论】:

迄今为止处理大文件的最佳方法。我的程序从消耗 8GB+ 到几乎没有。权衡是 CPU 使用率从 ~15% 到 ~40%,但文件的实际处理速度快了 70%。我整天都在权衡。谢谢! ??? 这对我来说似乎是最 Pythonic 的。谢谢!【参考方案6】:

如果你想要第 7 行

line = open("file.txt", "r").readlines()[7]

【讨论】:

整洁。但是你怎么close() 用这种方式打开文件呢? @0sh 我们需要关闭吗? 是的。我们需要在此之后关闭。当我们使用“with”打开文件时......它会自行关闭。 with open("file.txt", "r") as file:line = file.readlines()[7]。但请注意,这会将整个文件读入内存。【参考方案7】:

读取文件的速度令人难以置信。读取一个 100MB 的文件只需不到 0.1 秒(参见我的文章 Reading and Writing Files with Python)。因此,您应该完整阅读它,然后使用单行。

这里的大多数答案没有错,但风格不好。应始终使用with 打开文件,因为它确保文件再次关闭。

所以你应该这样做:

with open("path/to/file.txt") as f:
    lines = f.readlines()
print(lines[26])  # or whatever you want to do with this line
print(lines[30])  # or whatever you want to do with this line

巨大的文件

如果您碰巧有一个巨大的文件并且内存消耗是一个问题,您可以逐行处理它:

with open("path/to/file.txt") as f:
    for i, line in enumerate(f):
        pass  # process line i

【讨论】:

IMO 读取整个未知长度的文件是一种非常糟糕的风格,只读取前 30 行.. 什么是内存消耗.. 什么是无尽的流?跨度> @return42 这在很大程度上取决于应用程序。对于许多人来说,假设文本文件的大小比可用内存小得多是完全可以的。如果您碰巧有潜在的大文件,我已经编辑了我的答案。 谢谢你的补充,和alokanswer一样。抱歉,不,我认为这不取决于应用程序。 IMO 最好不要阅读比你需要的更多的行。 “读取文件速度非常快”我对此有异议。事实上,读取文件非常慢,数据密集型程序会尽可能少地这样做。在计算方面,0.1 秒远不及“快”。如果你只做一次可能没问题(在某些情况下),但如果你这样做 1000 次,则需要 100 秒,这在大多数情况下是无法接受的。 @michael dorst:我完全同意。这取决于您的应用程序,但我们需要考虑到他无论如何都必须阅读该文件。问题是:仅读取第 26 行和第 30 行与使用例如读取文件之间的速度差异是多少? 500 行。我假设它不会更多,因为我本来希望被提及。【参考方案8】:

其中一些很可爱,但可以更简单地完成:

start = 0 # some starting index
end = 5000 # some ending index
filename = 'test.txt' # some file we want to use

with open(filename) as fh:
    data = fin.readlines()[start:end]

print(data)

这将使用简单的列表切片,它会加载整个文件,但大多数系统会适当地最小化内存使用量,它比上面给出的大多数方法更快,并且适用于我的 10G+ 数据文件。祝你好运!

【讨论】:

【参考方案9】:

如果您的大文本文件file 结构严格(意味着每一行都具有相同的长度l),您可以使用n-th line

with open(file) as f:
    f.seek(n*l)
    line = f.readline() 
    last_pos = f.tell()

免责声明这仅适用于相同长度的文件!

【讨论】:

【参考方案10】:

您可以进行seek() 调用,将您的读取头定位到文件中的指定字节。除非您确切地知道在要读取的行之前在文件中写入了多少字节(字符),否则这对您没有帮助。也许您的文件是严格格式化的(每行是 X 字节数?)或者,如果您真的想要提高速度,您可以自己计算字符数(记住包括换行符等不可见字符)。

否则,您必须按照此处已经提出的众多解决方案之一阅读所需行之前的每一行。

【讨论】:

【参考方案11】:
def getitems(iterable, items):
  items = list(items) # get a list from any iterable and make our own copy
                      # since we modify it
  if items:
    items.sort()
    for n, v in enumerate(iterable):
      if n == items[0]:
        yield v
        items.pop(0)
        if not items:
          break

print list(getitems(open("/usr/share/dict/words"), [25, 29]))
# ['Abelson\n', 'Abernathy\n']
# note that index 25 is the 26th item

【讨论】:

罗杰,我最喜欢的人!这可以从 with 语句中受益。【参考方案12】:
with open("test.txt", "r") as fp:
   lines = fp.readlines()
print(lines[3])

test.txt 是文件名 在 test.txt 中打印第四行

【讨论】:

【参考方案13】:

这个怎么样:

>>> with open('a', 'r') as fin: lines = fin.readlines()
>>> for i, line in enumerate(lines):
      if i > 30: break
      if i == 26: dox()
      if i == 30: doy()

【讨论】:

没错,这比 Alok 的效率低,但我的使用 with 语句 ;)【参考方案14】:

如果您不介意导入,那么 fileinput 完全符合您的需要(这是您可以读取当前行的行号)

【讨论】:

【参考方案15】:

我更喜欢这种方法,因为它更通用,即您可以在文件、f.readlines() 的结果、StringIO 对象上使用它:

def read_specific_lines(file, lines_to_read):
   """file is any iterable; lines_to_read is an iterable containing int values"""
   lines = set(lines_to_read)
   last = max(lines)
   for n, line in enumerate(file):
      if n + 1 in lines:
          yield line
      if n + 1 > last:
          return

>>> with open(r'c:\temp\words.txt') as f:
        [s for s in read_specific_lines(f, [1, 2, 3, 1000])]
['A\n', 'a\n', 'aa\n', 'accordant\n']

【讨论】:

【参考方案16】:

这是我的小 2 美分,物有所值;)

def indexLines(filename, lines=[2,4,6,8,10,12,3,5,7,1]):
    fp   = open(filename, "r")
    src  = fp.readlines()
    data = [(index, line) for index, line in enumerate(src) if index in lines]
    fp.close()
    return data


# Usage below
filename = "C:\\Your\\Path\\And\\Filename.txt"
for line in indexLines(filename): # using default list, specify your own list of lines otherwise
    print "Line: %s\nData: %s\n" % (line[0], line[1])

【讨论】:

【参考方案17】:

对 Alok Singhal 的回答进行了更好的微小改动

fp = open("file")
for i, line in enumerate(fp,1):
    if i == 26:
        # 26th line
    elif i == 30:
        # 30th line
    elif i > 30:
        break
fp.close()

【讨论】:

【参考方案18】:

您可以使用某人已经提到的语法非常简单地做到这一点,但这是迄今为止最简单的方法:

inputFile = open("lineNumbers.txt", "r")
lines = inputFile.readlines()
print (lines[0])
print (lines[2])

【讨论】:

【参考方案19】:

文件对象有一个 .readlines() 方法,它会给你一个文件内容列表,每个列表项一行。之后,您就可以使用普通的列表切片技术了。

http://docs.python.org/library/stdtypes.html#file.readlines

【讨论】:

【参考方案20】:

@OP,你可以使用枚举

for n,line in enumerate(open("file")):
    if n+1 in [26,30]: # or n in [25,29] 
       print line.rstrip()

【讨论】:

【参考方案21】:
file = '/path/to/file_to_be_read.txt'
with open(file) as f:
    print f.readlines()[26]
    print f.readlines()[30]

使用 with 语句打开文件,打印第 26 和 30 行,然后关闭文件。简单!

【讨论】:

这不是一个有效的答案。在第一次调用readlines() 之后,迭代器将被耗尽,第二次调用将返回一个空列表或抛出一个错误(不记得是哪个)【参考方案22】:

要打印第 3 行,

line_number = 3

with open(filename,"r") as file:
current_line = 1
for line in file:
    if current_line == line_number:
        print(file.readline())
        break
    current_line += 1

原作者:弗兰克霍夫曼

【讨论】:

【参考方案23】:

相当快速和重点。

打印文本文件中的某些行。创建一个“lines2print”列表,然后 仅在枚举“在”lines2print 列表中时打印。 要摆脱多余的 '\n',请使用 line.strip() 或 line.strip('\n')。 我只是喜欢“列表理解”,并尽可能地尝试使用。 我喜欢用“with”方法来读取文本文件,以防止 出于任何原因打开文件。

lines2print = [26,30] # can be a big list and order doesn't matter.

with open("filepath", 'r') as fp:
    [print(x.strip()) for ei,x in enumerate(fp) if ei in lines2print]

或者如果列表很小,只需将列表作为列表输入到理解中。

with open("filepath", 'r') as fp:
    [print(x.strip()) for ei,x in enumerate(fp) if ei in [26,30]]

【讨论】:

【参考方案24】:

打印所需的行。 在所需行的上方/下方打印行。

def dline(file,no,add_sub=0):
    tf=open(file)
    for sno,line in enumerate(tf):
        if sno==no-1+add_sub:
         print(line)
    tf.close()

execute---->dline("D:\dummy.txt",6) 即 dline("file path", line_number, 如果你想要搜索行的上一行,给低 -1 1 这是可选的默认值为 0)

【讨论】:

【参考方案25】:

如果您想读取特定的行,例如在某个阈值行之后开始的行,那么您可以使用以下代码, file = open("files.txt","r") lines = file.readlines() ## convert to list of lines datas = lines[11:] ## raed the specific lines

【讨论】:

【参考方案26】:
f = open(filename, 'r')
totalLines = len(f.readlines())
f.close()
f = open(filename, 'r')

lineno = 1
while lineno < totalLines:
    line = f.readline()

    if lineno == 26:
        doLine26Commmand(line)

    elif lineno == 30:
        doLine30Commmand(line)

    lineno += 1
f.close()

【讨论】:

这简直太不合Python了。 给出错误的结果,因为你不能像那样使用 readlines 和 readline (它们都会改变当前的读取位置)。 我很抱歉在我的第一个代码中忽略了一个巨大的错误。错误已得到纠正,当前代码应按预期工作。感谢您指出我的错误,Roger Pate。【参考方案27】:

我认为这可行

 open_file1 = open("E:\\test.txt",'r')
 read_it1 = open_file1.read()
 myline1 = []
 for line1 in read_it1.splitlines():
 myline1.append(line1)
 print myline1[0]

【讨论】:

当你发布这个时,已经有十几个 readline 方法了——添加另一个只会增加混乱【参考方案28】:

从特定行读取:

n = 4   # for reading from 5th line
with open("write.txt",'r') as t:
     for i,line in enumerate(t):
         if i >= n:             # i == n-1 for nth line
            print(line)

【讨论】:

没有内置功能

以上是关于如何从文件中读取特定行(按行号)?的主要内容,如果未能解决你的问题,请参考以下文章

在一个非常大的文件中逐行读取特定的行

从 csv 读取特定(非连续)行

mySQL - 按行号搜索行?

使用java的输入输出流将一个文本文件的内容按行读取,每读一行就顺序添加行号,并写入到另一个文件中

如何在文本文件中查找行并导出行号

PHP:从文件中读取特定行