2010-12-03 75 views
2

如何从文件中读取n行而不是只读一行?我有一个有明确定义结构的文件,我愿做这样的事情:从Python中的文件(但不是全部)读取n行

for line1, line2, line3 in file: 
    do_something(line1) 
    do_something_different(line2) 
    do_something_else(line3) 

,但它不工作:

ValueError: too many values to unpack

现在我这样做:

for line in file: 
    do_someting(line) 
    newline = file.readline() 
    do_something_else(newline) 
    newline = file.readline() 
    do_something_different(newline) 
... etc. 

这很糟糕,因为我正在编写无休止的'newline = file.readline()'这是混乱的代码。 有没有什么聪明的方法来做到这一点? (我真的想避免一次读取整个文件,因为它很大)

+0

与downvote什么? – Yehonatan 2010-12-03 11:53:37

+0

`file`是Python中的一个迭代器,请参阅http:// stackoverflow。/ 434287 /什么是最蟒蛇式的方式来重复在列表块/ 434411#434411 – jfs 2010-12-04 15:34:02

回答

4

基本上,你的file是一个迭代器,它一次产生一行文件。这将您的问题变成了如何从迭代器中一次产生多个项目。该解决方案在this question中给出。请注意,函数islice位于itertools模块中,因此您必须从那里导入它。

0

如果你的目的是做同样的事情,为什么你需要每次迭代处理多行?

对于文件中的行是你的朋友。它通常比手动读取文件更有效率,无论是在IO性能还是内存方面。

+0

对不起,编辑,我想做不同的事情,以每一行一批n行,然后对另一批n个文件中的行做同样的事情 – 2010-12-03 03:06:42

1

for i in file产生str,所以你不能只是做for i, j, k in file和三个批次(试行a, b, c = 'bar'a, b, c = 'too many characters'和看的,b和c的值,以制定出为什么你的“太多的阅读值解包“)。

它不是完全清楚你的意思,但如果你正在做的每一行同样的事情,只是想停在某个点,然后像这样做:

for line in file_handle: 
    do_something(line) 
    if some_condition: 
     break # Don't want to read anything else 

(另外,不要不会使用file作为变量名称,因此您正在调整内置值。)

0

您是否知道有关数据行/格式长度的信息?如果是这样,你可以读取前n个字节(比如80 * 3)和f.read(240).split(“\ n”)[0:3]。

+0

不幸的是,它是巨大的xml'like文件,其中一些值可能有不同的长度 – 2010-12-03 03:05:01

+0

最大的文件有多大? 10K? 1MB? 100MB?我认为它太大而无法读取整个文件,但即使在100K下读取也会便宜/快速。除非你必须在紧密的循环中进行一百万次。 – 2010-12-03 03:10:59

+0

我现在拥有的文件是80MB,未来可能会有更大的文件;我不想将问题全部加载到内存中,因为这个问题经常出现(至少对我来说)) – 2010-12-03 03:16:56

0

如果你想能够一遍又一遍用这个数据,一个方法可能是这样:

lines = [] 
for line in file_handle: 
    lines.append(line) 

这会给你的行的列表,你可以再通过访问指数。另外,当你说一个巨大的文件时,它的大小很可能是微不足道的,因为python可以很快处理数千行。

3

如果是xml,为什么不使用lxml?

0

为什么你就不能这样做:

CTR = 0

在文件行:

if ctr == 0: 

    .... 

    elif ctr == 1: 

    .... 

    ctr = ctr + 1 

如果你发现如果/ elif的构建丑,你可以只创建哈希表或函数指针列表,然后执行:

对于文件中的行:

function_list[ctr]() 

或类似

2

你可以使用一个辅助函数是这样的:

def readnlines(f, n): 
    lines = [] 
    for x in range(0, n): 
     lines.append(f.readline()) 
    return lines 

然后,像你想你可以做一些事情:

while True: 
    line1, line2, line3 = readnlines(file, 3) 
    do_stuff(line1) 
    do_stuff(line2) 
    do_stuff(line3) 

话虽这么说,如果你是使用xml文件,如果使用真正的xml解析器,您可能会长期得到更高兴...

0

这听起来像你试图从磁盘并行读取......这是很难做到的。所有给你的解决方案都是现实和合法的。你不应该因为代码“看起来很丑陋”而让某些东西让你失望。最重要的是它的效率/效果如何,那么如果代码很混乱,你可以整理它,但不要寻找一种全新的方法来做某件事,因为你不喜欢这样做的一种方式看起来像在代码中。

至于内存不足,您可能需要退房pickle

0

这可以通过巧妙使用zip函数来实现。它很短,但是对于我的口味有点巫术(很难看出它是如何工作的)。它会切断最后没有填满组的所有行,这可能是好的或坏的,取决于你在做什么。如果你需要最后的线路,itertools.izip_longest可能会诀窍。

zip(*[iter(inputfile)] * 3) 

更明确地,灵活地做,这是垫埃克伯格的解决方案的修改:

def groupsoflines(f, n): 
    while True: 
     group = [] 
     for i in range(n): 
      try: 
       group.append(next(f)) 
      except StopIteration: 
       if group: 
        tofill = n - len(group) 
        yield group + [None] * tofill 
       return 
     yield group 

for line1, line2, line3 in groupsoflines(inputfile, 3): 
    ... 

注:如果在一个组的中途没有线路,它将填补None的空缺,以便您仍然可以将其解包。因此,如果文件中的行数可能不是3的倍数,则需要检查line2line3是否为None

2

itertools救援:

import itertools 
def grouper(n, iterable, fillvalue=None): 
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" 
    args = [iter(iterable)] * n 
    return itertools.izip_longest(fillvalue=fillvalue, *args) 


fobj= open(yourfile, "r") 
for line1, line2, line3 in grouper(3, fobj): 
    pass 
相关问题