只阅读特定的行

3zz*_*zzy 197 python file line

我正在使用for循环来读取文件,但我只想读取特定的行,比如第26行和第30行.是否有任何内置功能来实现这一目标?

谢谢

Alo*_*hal 241

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

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()
Run Code Online (Sandbox Code Playgroud)

请注意,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
Run Code Online (Sandbox Code Playgroud)

  • @Dan D.电力被高估了,人类在没有它的情况下相处了20多万年.;-)'with'使其更安全,更易读,更短一行. (26认同)
  • 为什么用于循环,我不认为你理解"大文件"的含义.循环将需要数年才能达到指数 (7认同)
  • `enumerate(x)`使用`x.next`,因此它不需要内存中的整个文件. (5认同)
  • 被高估了,python在没有它的情况下相处了13年 (5认同)
  • +1 如果整个文件没有像“linecache”那样加载到内存中,那么比我的解决方案更好。您确定“enumerate(fp)”不会这样做吗? (3认同)
  • 我的小牛肉是这样的A)你想用而不是开/关对,从而保持身体短,B)但身体不是那么短.听起来像速度/空间和Pythonic之间的权衡.我不确定最佳解决方案是什么. (3认同)

Ada*_*tan 144

快速回答:

f=open('filename')
lines=f.readlines()
print lines[25]
print lines[29]
Run Code Online (Sandbox Code Playgroud)

要么:

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

有一个更优雅的解决方案,用于提取许多行:linecache(由"python:如何跳转到一个巨大的文本文件中的特定行?",以前的stackoverflow.com问题).

引用上面链接的python文档:

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

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

如果文件可能非常大,并且在读入内存时会导致问题,那么采用@Alok的建议并使用enumerate()可能是个好主意.

总结:

  • 使用fileobject.readlines()for line in fileobject作为小文件的快速解决方案.
  • 使用linecache更优雅的解决方案,可以快速读取多个文件.
  • @ Alok的建议并使用enumerate()可能非常大的文件,并且不适合内存.请注意,使用此方法可能会因为按顺序读取文件而变慢.

  • 尼斯.我只是看了一下`linecache`模块的来源,看起来它在内存中读取整个文件.因此,如果随机访问比大小优化更重要,那么`linecache`是最好的方法. (6认同)
  • 与linecache.getlin('some_file',4)我得到第4行,而不是第5行. (6认同)

Ale*_*lli 29

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

def picklines(thefile, whatlines):
  return [x for i, x in enumerate(thefile) if i in whatlines]
Run Code Online (Sandbox Code Playgroud)

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

def yieldlines(thefile, whatlines):
  return (x for i, x in enumerate(thefile) if i in whatlines)
Run Code Online (Sandbox Code Playgroud)

这基本上只适用于循环 - 请注意,唯一的区别来自于在return语句中使用舍入而不是方括号,分别进行列表推导和生成器表达式.

此外应注意,尽管"行"和"文件"提到这些功能很多,很多更普遍的-他们会在工作的任何可迭代的,无论是打开的文件或任何其他的,返回的项目清单(或发电机)基于他们的进步项目数.所以,我建议使用更合适的通用名称;-).

  • @Mannaggia在这个答案中没有足够强调,但是“ whatlines”应该是一个“ set”,因为“ if whatlines”如果使用set而不是(sorted)列表,执行速度会更快。我没有首先注意到它,而是设计了自己的带有排序列表的丑陋解决方案(我不必每次都扫描列表,而`if i whatlines'只是这样做),但是性能差异可以忽略不计(和我的数据),这种解决方案要优雅得多。 (2认同)

Kin*_*Mak 27

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

import linecache
linecache.getline('Sample.txt', Number_of_Line)
Run Code Online (Sandbox Code Playgroud)

我希望这很快捷:)

  • 这会将整个文件读入内存。您最好调用file.read()。split('\ n')然后使用数组索引查找来获得感兴趣的行... (2认同)

小智 14

如果你想要第7行

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

  • 整齐.但是如何以这种方式打开文件时关闭()文件? (14认同)
  • 是的。我们需要在此之后关闭。当我们使用“with”打开文件时……它会自行关闭。 (3认同)

Mar*_*oma 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
Run Code Online (Sandbox Code Playgroud)

巨大的文件

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

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

  • “读取文件的速度非常快”我对此表示异议。事实上,读取文件的速度非常慢,数据密集型程序会竭尽全力尽可能少地读取文件。从计算角度来说,0.1 秒远谈不上“快”。如果您只执行一次,也许还可以(在某些情况下),但如果您执行 1000 次,则需要 100 秒,而这在大多数情况下是无法接受的。 (2认同)

new*_*ver 9

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

让我们从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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

并回答原来的问题:

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

  • 迄今为止,处理大文件的最佳方法。我的程序从消耗 8GB+ 到几乎没有。权衡是 CPU 使用率从 ~15% 上升到 ~40%,但文件的实际处理速度提高了 70%。我会整天权衡利弊。谢谢! (2认同)
  • 这对我来说似乎是最pythonic的。谢谢! (2认同)

Wil*_*ill 6

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

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)
Run Code Online (Sandbox Code Playgroud)

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


Mic*_*ner 6

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

with open(file) as f:
    f.seek(n*l)
    line = f.readline() 
    last_pos = f.tell()
Run Code Online (Sandbox Code Playgroud)

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


Rom*_*man 5

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

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


小智 5

with open("test.txt", "r") as fp:
   lines = fp.readlines()
print(lines[3])
Run Code Online (Sandbox Code Playgroud)

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