将文件指针倒回到上一行Python文件IO

时间:2013-07-16 20:56:55

标签: python file-io

我正在阅读格式为

的大型基因文件
>GeneID
ACTCTCTCTATATATATATAT\n
GCTCTGCTTCTAGAGAGAGTG\n
TCTATTTGTTTATATATCTTT\n
>GeneID
GCTCTGCTTCTAGAAATTCCC\n
ACTCTGTATATATTTTCAAAA\n
GCTCTGCTTCTAGAGAGAGTG\n

每个基因以>开头。然后是一个唯一的ID。来自该基因的核苷酸后。 不幸的是,生成了这个文件,因此每个序列行之间都有换行符。

我需要在每个序列中读取一个连续的字符串。所以,我一直在使用下一个方法(如下所示)。

for line in filer:
    if line.startswith(">"):

        # Find Sequences
        seq_seg = next(filer)
        seq = ""

        # Concatenate lines until find next gene
        while not (seq_seg.startswith(">")):
            seq += seq_seg.strip()  # Get rid of '\n'
            seq_seg = next(filer)

我发现我的脚本只占用了文件中的一半基因,因为在使while循环失败的条件下调用next时,文件指针指向下一个基因ID,然后在下一次迭代时对于for循环执行,它将移动到下一个文件。

有没有办法将文件指针倒回到前一行,所以我的for循环将其作为新基因捕获?

我见过类似的问题,但没有一个问题涉及我用

阅读文件的具体方式
  for line in file:
        #do stuff

4 个答案:

答案 0 :(得分:3)

我会使用生成器而不是跳过线(有些东西告诉我这可以大大简化):

def parse_file(file):
    id = ''
    gene = ''

    for line in file:
        if line.startswith('>'):
            if gene:
                yield id, gene

            id = line[1:]
            gene = ''
        else:
            gene += line.strip()
    else:
        yield id, gene # Final gene

现在,您可以使用几行代码安全地迭代整个事情:

with open('file.txt', 'r') as handle:
    for gene_id, nucleotides in parse_file(handle):
        print gene_id, nucleotides

还有pyfasta

itertools的更一般的功能:

def grouper(line):
    return line.startswith('>') and line[1:]

def itersplit(it, pred):
    groups = (list(group) for key, group in itertools.groupby(it, pred))
    yield from zip(groups, groups)

def parse(file):
    for key, group in itersplit(file, grouper):
        yield key[0], ''.join(group)

答案 1 :(得分:1)

  

有没有办法将文件指针倒回到前一行,所以我的for循环将其作为新基因捕获?

在Python 3中,没有。您不能将文件迭代与文件指针上的显式操作混合在一起。

在Python 2中,也许吧。但这只是偶然的,这就是它在3.0中被禁止的原因,并不保证在每种情况下都能正常工作。所以,你不应该这样做。

更好的方法是询问如何回放迭代器。答案是itertools。您可以使用tee来提前查看。您可以将迭代器重新绑定到chain([pushed_back_value], iterator)。等等。

但是,正如其他人所指出的那样,有一种更好的方法可以做到这一点。你真的不需要向前看回到这里,你只需要分组。您也可以使用itertools执行此操作,但在这种情况下,您可以轻松地执行此操作,就像Blender所示。

答案 2 :(得分:1)

以下是另一种使用remmap的方法:

import mmap, re

with open(your_file) as fin:
    mm = mmap.mmap(fin.fileno(), 0, access=mmap.ACCESS_READ)
    for match in re.finditer('>([^\n]+)([^>]*)', mm, flags=re.DOTALL):
        print match.group(1), match.group(2).replace('\n', '')

#GeneID1 ACTCTCTCTATATATATATATGCTCTGCTTCTAGAGAGAGTGTCTATTTGTTTATATATCTTT
#GeneID2 GCTCTGCTTCTAGAAATTCCCACTCTGTATATATTTTCAAAAGCTCTGCTTCTAGAGAGAGTG

这样做可以将整个文件视为字符串,但是将使用提供文件部分的操作系统来完成正则表达式。由于它使用finditer,我们也没有在内存中构建结果。

答案 3 :(得分:0)

有更简单的方法来读取fasta文件,例如:

entries = []
for line in filer:
    if line.startswith('>'):
        entries.append((line.rstrip()[1:], []))
    else:
        entries[-1][1].append(line.rstrip())

这将为您提供元组列表。第一个元素是序列ID,第二个元素是序列列表。

在此之后加入序列很容易:

entries = [(x, "".join(y)) for x,y in entries]