use*_*503 102 python text-files
以下代码是否有其他替代方法:
startFromLine = 141978 # or whatever line I need to jump to
urlsfile = open(filename, "rb", 0)
linesCounter = 1
for line in urlsfile:
if linesCounter > startFromLine:
DoSomethingWithThisLine(line)
linesCounter += 1
Run Code Online (Sandbox Code Playgroud)
如果我正在(~15MB)使用未知但不同长度的行处理一个巨大的文本文件,并且需要跳转到我事先知道的特定行?当我知道我至少可以忽略文件的前半部分时,我会逐个处理它们.寻找更优雅的解决方案,如果有的话.
Ada*_*eld 111
如果没有在文件中读取至少一次就无法跳转,因为你不知道换行的位置.你可以这样做:
# Read in the file once and build a list of line offsets
line_offset = []
offset = 0
for line in file:
line_offset.append(offset)
offset += len(line)
file.seek(0)
# Now, to skip to line n (with the first line being line 0), just do
file.seek(line_offset[n])
Run Code Online (Sandbox Code Playgroud)
Joh*_*ood 26
该
linecache模块允许从Python源文件获取任何行,同时尝试使用缓存在内部进行优化,这是从单个文件中读取许多行的常见情况.traceback模块使用它来检索源行以包含在格式化的回溯中...
Jar*_*die 20
如果线条的长度不同,你真的没有那么多的选项...你可能需要处理行结束字符以了解你何时进展到下一行.
但是,您可以通过将最后一个参数更改为"打开"到非0的内容来显着提高速度并减少内存使用量.
0表示文件读取操作是无缓冲的,这非常慢并且磁盘密集.1表示文件是行缓冲的,这将是一种改进.大于1的任何东西(比如8k ......即:8096或更高)将文件的块读取到内存中.你仍然可以访问它for line in open(etc):,但是python一次只能进行一些操作,在处理后丢弃每个缓冲的块.
我遇到了同样的问题(需要从大文件特定行中检索)。
\n\n当然,我可以每次运行文件中的所有记录,并在计数器等于目标行时停止它,但在您想要获取复数个特定行的情况下,它不能有效地工作。这导致主要问题得到解决 - 如何直接处理到文件的必要位置。
\n\n我找到了下一个决定:\n首先,我完成了字典,其中包含每行的起始位置(键是行号,值 \xe2\x80\x93 前一行的累积长度)。
\n\nt = open(file,\xe2\x80\x99r\xe2\x80\x99)\ndict_pos = {}\n\nkolvo = 0\nlength = 0\nfor each in t:\n dict_pos[kolvo] = length\n length = length+len(each)\n kolvo = kolvo+1\nRun Code Online (Sandbox Code Playgroud)\n\n最终,目标函数:
\n\ndef give_line(line_number):\n t.seek(dict_pos.get(line_number))\n line = t.readline()\n return line\nRun Code Online (Sandbox Code Playgroud)\n\nt.seek(line_number) \xe2\x80\x93 命令,执行文件修剪直至行起始。\n因此,如果您接下来提交 readline \xe2\x80\x93 您将获得目标行。
\n\n使用这种方法我节省了大量时间。
\n小智 5
由于没有阅读前无法确定所有行的长度,因此您别无选择,只能在开始行之前遍历所有行。您所要做的就是使它看起来不错。如果文件确实很大,那么您可能要使用基于生成器的方法:
from itertools import dropwhile
def iterate_from_line(f, start_from_line):
return (l for i, l in dropwhile(lambda x: x[0] < start_from_line, enumerate(f)))
for line in iterate_from_line(open(filename, "r", 0), 141978):
DoSomethingWithThisLine(line)
Run Code Online (Sandbox Code Playgroud)
注意:此方法的索引为零。
您可以使用 mmap 来查找线条的偏移量。MMap 似乎是处理文件最快的方法
例子:
with open('input_file', "r+b") as f:
mapped = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
i = 1
for line in iter(mapped.readline, ""):
if i == Line_I_want_to_jump:
offsets = mapped.tell()
i+=1
Run Code Online (Sandbox Code Playgroud)
然后使用 f.seek(offsets) 移动到您需要的行
我很惊讶没有人提到伊丽丝
line = next(itertools.islice(Fhandle,index_of_interest,index_of_interest+1),None) # just the one line
Run Code Online (Sandbox Code Playgroud)
或者如果您想要整个文件的其余部分
rest_of_file = itertools.islice(Fhandle,index_of_interest)
for line in rest_of_file:
print line
Run Code Online (Sandbox Code Playgroud)
或者如果您想要文件中的其他所有行
rest_of_file = itertools.islice(Fhandle,index_of_interest,None,2)
for odd_line in rest_of_file:
print odd_line
Run Code Online (Sandbox Code Playgroud)
没有一个答案特别令人满意,因此这里有一个小片段可以提供帮助。
class LineSeekableFile:
def __init__(self, seekable):
self.fin = seekable
self.line_map = list() # Map from line index -> file position.
self.line_map.append(0)
while seekable.readline():
self.line_map.append(seekable.tell())
def __getitem__(self, index):
# NOTE: This assumes that you're not reading the file sequentially.
# For that, just use 'for line in file'.
self.fin.seek(self.line_map[index])
return self.fin.readline()
Run Code Online (Sandbox Code Playgroud)
用法示例:
In: !cat /tmp/test.txt
Out:
Line zero.
Line one!
Line three.
End of file, line four.
In:
with open("/tmp/test.txt", 'rt') as fin:
seeker = LineSeekableFile(fin)
print(seeker[1])
Out:
Line one!
Run Code Online (Sandbox Code Playgroud)
这涉及执行大量文件查找,但对于无法将整个文件放入内存的情况非常有用。它执行一次初始读取以获取行位置(因此它确实读取整个文件,但不会将其全部保留在内存中),然后每次访问都会在事后进行文件查找。
我根据用户的判断在 MIT 或 Apache 许可证下提供上面的代码片段。