如何跳转到大型文本文件中的特定行?

2025-01-09 08:46:00
admin
原创
118
摘要:问题描述:下面的代码还有其他替代方案吗:startFromLine = 141978 # or whatever line I need to jump to urlsfile = open(filename, "rb", 0) linesCounter = 1 for line i...

问题描述:

下面的代码还有其他替代方案吗:

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),其中包含未知但长度不同的行,并且需要跳转到我事先知道的某一行?当我知道至少可以忽略文件的前半部分时,我感觉逐行处理它们很糟糕。如果有的话,寻找更优雅的解决方案。


解决方案 1:

如果不至少读取一次文件,您就无法跳转,因为您不知道换行符在哪里。您可以执行以下操作:

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

解决方案 2:

行缓存:

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

解决方案 3:

如果行的长度不同,那么您实际上没有那么多选择……遗憾的是,您需要处理行尾字符才能知道何时进展到下一行。

但是,您可以通过将最后一个参数“open”更改为非 0 的值来显著加快速度并减少内存使用量。

0 表示文件读取操作是无缓冲的,这非常慢并且占用大量磁盘空间。1 表示文件是行缓冲的,这将是一个改进。任何大于 1(例如 8 kB,即 8192 或更高)的值都会将文件块读入内存。您仍然可以通过 访问它for line in open(etc):,但 python 每次只读取一点,处理完每个缓冲块后将其丢弃。

解决方案 4:

我可能被丰富的内存宠坏了,但 15 M 并不算大。readlines()对于这种大小的文件,我通常使用 读入内存。之后访问一行就很简单了。

解决方案 5:

我很惊讶没有人提到islice。它只有一行!

from itertools import islice

line = next(islice(Fhandle, index_of_interest, index_of_interest+1), None)

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

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

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

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

解决方案 6:

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

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

我发现了下一个决定:首先,我完成了字典,其中包含每行的起始位置(关键是行号,值是前几行的累计长度)。

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) – 执行文件修剪直至行开头的命令。因此,如果您接下来提交 readline – 您将获得目标行。

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

解决方案 7:

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

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)

注意:在此方法中索引是从零开始的。

解决方案 8:

您可以使用 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(offsets) 移动到您需要的行

解决方案 9:

没有一个答案特别令人满意,所以这里有一小段代码可以提供帮助。

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

使用示例:

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!

这涉及执行大量文件搜索,但在无法将整个文件放入内存的情况下很有用。它会进行一次初始读取以获取行位置(因此它会读取整个文件,但不会将其全部保存在内存中),然后每次访问后都会进行文件搜索。

我根据用户的判断,根据 MIT 或 Apache 许可提供上述代码片段。

解决方案 10:

如果您不想读取内存中的整个文件,您可能需要采用除纯文本之外的其他格式。

当然,这一切都取决于您要做什么,以及您跳转文件的频率。

例如,如果你要多次跳转到同一个文件中的行,并且你知道该文件在处理时不会发生变化,你可以这样做:

首先,遍历整个文件,并记录一些关键行号的“搜索位置”(例如,每 1000 行),

然后如果你想要第 12005 行,跳转到 12000 的位置(你已经记录了)然后读取 5 行,你就会知道你在第 12005 行等等

解决方案 11:

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

编辑:您可以使用linecache.getline(filename, lineno)函数,它将返回行 lineno 的内容,但只有在将整个文件读入内存后才能返回。如果您随机访问文件内的行(因为 python 本身可能想要打印回溯),这很好,但对于 15MB 的文件来说并不好。

解决方案 12:

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

  • 您想要哪条线路?

  • 计算索引文件中相应行号的字节偏移量(因为索引文件的行大小是恒定的,所以这是可能的)。

  • 使用 seek 或其他方式直接跳转以从索引文件中获取行。

  • 解析以获取实际文件相应行的字节偏移量。

解决方案 13:

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

否则,您能做的最好的事情就是readlines()。如果您不想读取全部 15MB,则可以使用该sizehint参数至少readline()用较少的调用次数替换大量 s readlines()

解决方案 14:

如果您处理的是文本文件并且基于Linux 系统,则可以使用 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)

解决方案 15:

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)

解决方案 16:

@george 巧妙地建议使用mmap,它大概使用了系统调用mmap。这是另一种表现形式。

import mmap

LINE = 2  # your desired line

with open('data.txt','rb') as i_file, mmap.mmap(i_file.fileno(), length=0, prot=mmap.PROT_READ) as data:
  for i,line in enumerate(iter(data.readline, '')):
    if i!=LINE: continue
    pos = data.tell() - len(line)
    break

  # optionally copy data to `chunk`
  i_file.seek(pos)
  chunk = i_file.read(len(line))

print(f'line {i}')
print(f'byte {pos}')
print(f'data {line}')
print(f'data {chunk}')

解决方案 17:

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

def skipton(infile, n):
    with open(infile,'r') as fi:
        for i in range(n-1):
            fi.next()
        return fi.next()
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3807  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2690  
  敏捷每日站会作为敏捷项目管理中的关键环节,对于提升产品生命周期管理(PLM)效率有着不可忽视的作用。PLM涵盖了产品从概念产生到最终报废的全过程管理,涉及众多环节与人员,而每日站会能够通过优化沟通机制,让信息在团队中快速、准确地流动,从而推动整个PLM流程更加顺畅、高效。接下来,我们将深入探讨如何通过四步优化沟通机制,...
plm系统   130  
  在企业的发展进程中,产品生命周期管理(PLM)项目管理至关重要,而数据驱动决策则是提升PLM项目管理效能的关键手段。通过运用合适的分析模型,企业能够从海量数据中挖掘有价值的信息,为决策提供有力支撑,进而优化产品全生命周期的各个环节。以下将详细介绍助力PLM项目管理实现数据驱动决策的5大分析模型。需求分析模型需求分析是P...
plm系统功能介绍   133  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与运营中扮演着至关重要的角色。它涵盖了从产品概念设计到退役的全流程管理,确保产品数据的有效整合与协同。然而,在复杂多变的商业环境中,黑天鹅事件随时可能降临,给企业带来难以预估的冲击。这些意外事件具有不可预测性、极大的影响力和事后的可解释性等特点,会对PLM系统的正常运...
plm系统的主要功能模块   131  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用