仅读取特定行


Answers:


253

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

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-1对于nth行。


在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

8
enumerate(x)使用x.next,因此它不需要整个文件在内存中。
Alok Singhal 2010年

3
我的小牛肉是这样的:A)您想与而不是打开/关闭对一起使用,从而使身体短,B)但是身体不是那么短。听起来像是在速度/空间和Python风格之间进行权衡。我不确定最佳解决方案是什么。
Hamish Grubijan 2010年

5
与被高估了,没有它的python相处了13年之久
Dan D.

38
@Dan D.电力被高估了,人类没有它就被罚款二十万多年。;-)'with'使它更安全,更易读,并且缩短了一行。
罗曼·文森特

9
为什么使用for循环,我认为您不了解的含义big file。该循环将需要数年才能达到指数
devssh

159

快速答案:

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:如何跳转到巨大的文本文件中的特定行?”,这是上一个stackoverflow.com问题)。

引用上面链接的python文档:

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

将更4改为所需的行号,然后打开。请注意,由于计数从零开始,因此4将带来第五行。

如果文件可能很大,并且在读入内存时引起问题,则最好采用@Alok的建议并使用enumerate()

结论:

  • 使用fileobject.readlines()for line in fileobject作为小型文件的快速解决方案。
  • 使用linecache一个更优雅的解决方案,这将是相当快的读取许多文件,可能反复。
  • 听@Alok的建议,将其enumerate()用于可能非常大且不适合内存的文件。请注意,使用此方法可能会变慢,因为文件是按顺序读取的。

7
真好 我只是查看了linecache模块的源代码,看起来它读取了内存中的整个文件。因此,如果随机访问比大小优化更重要,那linecache是最好的方法。
Alok Singhal'1

7
使用linecache.getlin('some_file',4)我得到第四行,而不是第五行。
胡安

有趣的事实:如果在第二个示例中使用集合而不是列表,则会获得O(1)运行时间。在列表中查找的是O(n)。内部集合表示为散列,这就是为什么要获得O(1)运行时间的原因。在此示例中,这没什么大不了的,但是如果使用大量数字,并且关心效率,那么使用集是可行的方法。
雷迪

linecache现在似乎仅适用于python源文件
Paul H

您还可以使用linecache.getlines('/etc/passwd')[0:4]来读取第一,第二,第三和第四行。
zyy

30

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

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语句中使用了舍入而不是正方形的括号,分别使列表理解和生成器表达式成为可能。

此外应注意,尽管“线”,并注明“文件”这些功能很多,很多更普遍的-他们会在工作的任何可迭代的,无论是打开的文件或任何其他的,返回的项目清单(或发电机)根据其渐进项编号。因此,我建议使用更适当的通用名称;-)。


@ephemient,我不同意- genexp读起来流畅而完美。
Alex Martelli 2010年

优秀而优雅的解决方案,谢谢!实际上,生成器表达式甚至应支持大文件。没有比这更优雅的了吗?:)
Samuel Lampa 2014年

很好的解决方案,这与@AdamMatan提出的解决方案相比如何?Adam解决方案可以利用更多信息(行号单调增加),因此可能更快,因为这可能导致提前停止。我有一个10GB的文件,无法加载到内存中。
Mannaggia 2014年

2
@Mannaggia在此答案中,它的强调不够,但是whatlines应该是set,因为if i in whatlines使用set列表而不是(sorted)列表会更快地执行。我没有先注意到它,而是设计了自己的带排序列表的丑陋解决方案(我不必每次都扫描列表,if i in whatlines只是这样做了),但是性能差异可以忽略不计(根据我的数据),这解决方案要优雅得多。
维克多(Victor K)

28

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

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

我希望这是方便快捷的:)


1
希望这是最理想的解决方案。
maniac_user

2
这会将整个文件读入内存。您不妨调用file.read()。split('\ n'),然后使用数组索引查找来获取感兴趣的行...
duhaime,2018年

你能提供一个例子@duhaime
匿名

14

如果你要第7行

line = open(“ file.txt”,“ r”)。readlines()[7]

14
整齐。但是close(),以这种方式打开文件时如何处理?
Milo Wielondek

1
@ 0sh我们需要关闭吗?
Ooker 2015年

1
是。我们需要在此之后关闭。当我们使用“ with”打开文件时...它会自行关闭。
reetesh11

10

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

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

切片通常包含一部分序列的对象。使用下标符号[]创建切片,当给出多个变量时(例如在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]

1
到目前为止,处理大文件的最佳方法。我的程序从消耗8GB +变成几乎没有。传统的问题是CPU使用率从15%增至40%,但是文件的实际处理速度提高了70%。我会整天走这个陷阱。谢谢!🎉🎉🎉–
GollyJer

1
对我来说,这似乎是最pythonic的。谢谢!
ipetrik '18

10

读取文件的速度非常快。读取100MB的文件只需不到0.1秒的时间(请参阅我的文章使用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 '18

@ return42这在很大程度上取决于应用程序。对于许多人来说,完全可以假设文本文件的大小比可用内存小。如果您碰巧有潜在的大文件,我已经编辑了答案。
马丁·托马

感谢您的添加,这与alok answer相同。抱歉,我不认为这取决于应用程序。IMO总是最好不要再读更多行。
return42 '18 -10-4

7

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

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 +数据文件上运行。祝好运!


4

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

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


3

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

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

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


2

这个怎么样:

>>> 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语句;)
Hamish Grubijan 2010年

2

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


2
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语句。
Hamish Grubijan 2010年

2

我更喜欢这种方法,因为它更具通用性,也就是说,您可以在文件上,在结果上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']

2

这是我的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])

2

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()


1

@OP,可以使用枚举

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

1
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()迭代器的第一次调用将用尽之后,第二次调用将返回一个空列表或引发错误(不记得是哪个)
Paul H

1

您可以使用已经有人提到过的这种语法非常简单地执行此操作,但这是迄今为止最简单的方法:

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

1

要打印第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

原作者:弗兰克·霍夫曼


1

相当快而且很关键。

在文本文件中打印某些行。创建一个“ 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]

或者,如果list很小,只需在列表中输入list作为理解即可。

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

0

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

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)


0

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


-1
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()

7
这和它一样令人难以置信。
SilentGhost 2010年

给出错误的结果,因为您不能使用像这样的读取行和读取行(它们各自更改当前读取位置)。

对不起,我在第一个代码中忽略了一个巨大的错误。该错误已得到纠正,当前代码应按预期工作。感谢您指出我的错误,Roger Pate。
inspectorG4dget 2010年

-1

我认为这会工作

 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方法-添加另一种方法只会增加混乱
duhaime
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.