下面的代码是否有其他替代方案:

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

如果我正在处理一个巨大的文本文件 (~15MB) 行未知但长度不同,并且需要跳转到我事先知道的特定行?当我知道我至少可以忽略文件的前半部分时,我对逐一处理它们感到很糟糕。寻找更优雅的解决方案(如果有)。

有帮助吗?

解决方案

linecache

  

linecache 模块允许任何人获得任何来自Python源文件的行,同时尝试使用缓存在内部进行优化,这是从单个文件中读取许多行的常见情况。 traceback 模块使用它来检索源代码行包含在格式化的追溯中......

其他提示

如果没有在文件中读取至少一次,就无法前进,因为你不知道换行的位置。你可以这样做:

# 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])

如果线条的长度不同,你真的没有那么多选项...你可能需要处理行结束字符以了解你何时进展到下一行。

但是,您可以通过将最后一个参数更改为<!>来显着加快速度并减少内存使用量;打开<!>不是0的东西。

0表示文件读取操作是无缓冲的,这非常慢并且磁盘密集。 1表示文件是行缓冲的,这将是一种改进。大于1的任何东西(比如8k ......即:8096或更高)将文件的块读取到内存中。您仍然可以通过for line in open(etc):访问它,但是python一次只能进行一些操作,在处理完每个缓冲的块后丢弃它。

我可能被丰富的公羊宠坏了,但15米并不大。使用readlines()读入内存是我通常使用这种大小的文件。之后访问一行是微不足道的。

由于无法在不读取所有行的情况下确定所有行的长度,因此您别无选择,只能在起始行之前遍历所有行。你所能做的就是让它看起来不错。如果文件非常庞大,那么您可能希望使用基于生成器的方法:

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)

注意:基于此方法,索引为零。

我很惊讶没人提到islice

line = next(itertools.islice(Fhandle,index_of_interest,index_of_interest+1),None) # just the one line

或者如果你想要文件的其余部分

rest_of_file = itertools.islice(Fhandle,index_of_interest)
for line in rest_of_file:
    print line

或者如果你想要文件中的每一行

rest_of_file = itertools.islice(Fhandle,index_of_interest,None,2)
for odd_line in rest_of_file:
    print odd_line

如果您事先知道文件中的位置(而不是行号),则可以使用 file.seek()去那个位置。

修改:您可以使用 linecache。 getline(filename,lineno)函数,它将返回行lineno的内容,但只有在将整个文件读入内存之后。好的,如果你从文件中随机访问行(就像python本身可能想要打印回溯一样)但对15MB文件不好。

如果您不想在内存中读取整个文件..您可能需要提供除纯文本以外的某种格式。

当然这一切都取决于你想要做什么,以及你多久跳过一次文件。

例如,如果你要在同一个文件中多次跳到,并且你知道该文件在使用它时没有改变,你可以这样做:
首先,遍历整个文件,并记录<!> quot; seek-location <!> quot;一些关键行数(例如,1000行),
然后,如果您想要12005行,请跳转到12000(您已录制)的位置,然后读取5行,您将知道您在12005行 等等

什么生成了您要处理的文件?如果它在您的控制之下,您可以在附加文件时生成一个索引(哪一行位于哪个位置。)。索引文件可以是固定行大小(空格填充或0填充数字)并且肯定会更小。从而可以快速读取和处理。

  • 你想要哪条线?
  • 计算索引文件中相应行号的字节偏移量(可能是因为索引文件的行大小是恒定的)。
  • 使用seek或其他方式直接跳转以从索引文件中获取该行。
  • 解析以获取实际文件相应行的字节偏移量。

我遇到了同样的问题(需要从特定文件的特定行检索)。

当然,我可以每次遍历文件中的所有记录并在计数器等于目标行时停止它,但是当您想要获得多个特定行时,它不能有效地工作。这导致了主要问题的解决 - 如何直接处理文件的必要位置。

我发现了下一个决定: 首先,我用每行的起始位置完成了字典(键是行号,值<!>#8211;前一行的累计长度)。

t = open(file,’r’)
dict_pos = {}

kolvo = 0
length = 0
for each in t:
    dict_pos[kolvo] = length
    length = length+len(each)
    kolvo = kolvo+1

最终,目标函数:

def give_line(line_number):
    t.seek(dict_pos.get(line_number))
    line = t.readline()
    return line

t.seek(line_number)<!>#8211;执行文件修剪直到行初始化的命令。 所以,如果你下次提交readline <!>#8211;你获得目标线。

使用这种方法我节省了大部分时间。

这些行本身是否包含任何索引信息?如果每行的内容类似于<!>“<line index>:Data <!>”,则seek()方法可用于对文件进行二进制搜索,即使Data的数量是变量。你要寻找文件的中点,读一行,检查它的索引是否高于或低于你想要的那个,等等。

否则,你能做的最好的就是readlines()。如果您不想读取所有15MB,则可以使用sizehint参数至少用少量的readline()调用来替换大量的<=>。

这是一个使用'readlines(sizehint)'一次读取一行行的示例。 DNS指出了解决方案。我写这个例子是因为这里的其他例子是单行导向的。

def getlineno(filename, lineno):
    if lineno < 1:
        raise TypeError("First line is line 1")
    f = open(filename)
    lines_read = 0
    while 1:
        lines = f.readlines(100000)
        if not lines:
            return None
        if lines_read + len(lines) >= lineno:
            return lines[lineno-lines_read-1]
        lines_read += len(lines)

print getlineno("nci_09425001_09450000.smi", 12000)

您可以使用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

然后使用f.seek(偏移)移动到您需要的行

如果您正在处理文本文件 <!>放大器;基于 linux system ,您可以使用linux命令。点击 对我来说,这很有效!

import commands

def read_line(path, line=1):
    return commands.getoutput('head -%s %s | tail -1' % (line, path))

line_to_jump = 141978
read_line("path_to_large_text_file", line_to_jump)

可以使用此函数返回第n行:

def skipton(infile, n):
    with open(infile,'r') as fi:
        for i in range(n-1):
            fi.next()
        return fi.next()
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top