我正在使用 for
循环读取文件,但我只想读取特定的行,比如第 #26
行和 #30
行。有没有内置的功能可以实现这个要求呢?
如果要读取的文件很大,而且您不想一次性将整个文件读入内存:
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()
请注意,第 n
行的 i == n-1
。
在 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
linecache
那样加载到内存中,则比我的解决方案更好。您确定enumerate(fp)
不会这样做吗? - Adam Matanenumerate(x)
使用 x.next
,因此它不需要将整个文件存储在内存中。 - Alok Singhal简短回答:
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?",一个之前的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
实现更加优雅的解决方案,并且速度相当快。enumerate()
。请注意,由于该方法是按顺序读取文件的,因此可能会变慢。linecache
模块的源代码,看起来它会将整个文件读入内存中。因此,如果随机访问比尺寸优化更重要,那么使用linecache
是最好的方法。 - Alok Singhallinecache
现在似乎只适用于 Python 源文件。 - Paul Hlinecache.getlines('/etc/passwd')[0:4]
来读取第一、二、三和四行。 - zyy为了提供另一种解决方案:
import linecache
linecache.getline('Sample.txt', Number_of_Line)
希望这个能够快速且容易 :)
@anon
''.join(file.readlines()).split('\n'))[5:10]` 给出了第6到10行的例子。不建议使用,因为它会将整个文件读入内存。 - questionto42一种快速而紧凑的方法可能是:
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
语句中使用了圆括号而不是方括号,分别生成列表推导和生成器表达式。
进一步注意,尽管提到了“行”和“文件”,但这些函数更加通用,它们可以作用于任何可迭代对象,无论是打开的文件还是其他任何东西,根据它们的递增项数返回一个列表(或生成器)中的项目。因此,建议使用更为通用的名称;-)。
whatlines
应该是一个 set
,因为使用集合比(排序后的)列表更快地执行 if i in whatlines
。我一开始没有注意到这一点,而是设计了自己丑陋的解决方案,使用了排序后的列表(在那里我不必每次扫描列表,而 if i in whatlines
刚好做到了这一点)��但性能差异微不足道(对于我的数据),而这个解决方案更加优雅。 - Victor K为了完整起见,这里是另一种选择。
让我们从Python文档中的定义开始:
切片通常包含序列的一部分的对象。使用下标符号[]创建切片时,如果给出几个数字,则在数字之间使用冒号,例如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]
line = open("file.txt", "r").readlines()[7]
with open("file.txt", "r") as file:
打开文件,然后通过line = file.readlines()[7]
读取第8行内容。但请注意,这将整个文件读入内存。 - questionto42读取文件非常快。读取一个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
有些很可爱,但可以更简单地完成:
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+数据文件。祝好运!
如果你的大型文本文件file
是严格结构化的(即每行具有相同的长度l
),则可以为第n
行使用以下方法:
with open(file) as f:
f.seek(n*l)
line = f.readline()
last_pos = f.tell()
免责声明:此方法仅适用于长度相同的文件!
否则,您需要按照已经在此处提出的解决方案之一,逐行读取所需行之前的所有行。