在python文件处理中混合readline()和行迭代器是否安全?

时间:2011-01-21 18:12:08

标签: python file-io

使用readline()读取某些行并使用for line in file是否安全,是否可以保证使用相同的文件位置?

通常,我想忽略第一行(标题),所以我这样做:

FI = open("myfile.txt")
FI.readline()             # disregard the first line
for line in FI:
    my_process(line)
FI.close()

这是否安全,即是否保证在迭代行时使用相同的文件位置变量?

3 个答案:

答案 0 :(得分:16)

不,it isn't safe

  

使用预读的结果   缓冲区,将next()与其他组合   文件方法(如readline())可以   不行。

您可以使用next()跳过第一行。您还应该测试StopIteration,如果文件为空,将会引发该问题。

with open('myfile.txt') as f:
    try:
        header = next(f)
    except StopIteration as e:
        print "File is empty"
    for line in f:
        # do stuff with line

答案 1 :(得分:4)

从长远来看,这很好。它忽略了您正在处理文件并使用任何序列的事实。此外,使用明确的迭代器对象(rdr)可以跳过 for 循环体内的行,而不会弄乱任何东西。

with open("myfile.txt","r") as source:
    rdr= iter(source)
    heading= next(rdr)
    for line in rdr:
        process( line )

答案 2 :(得分:2)

如果机制得到控制是安全的。

=============================

readline()指令后进行迭代没有问题

但是有一个在迭代后执行 readline()

我使用此文本创建了一个'rara.txt'文件(由于Windows下'\ r \ n'行的结尾,每行的长度为5)

1AA
2BB
3CC
4DD
5EE
6FF
7GG
8HH
9II
10j
11k
12l
13m
14n
15o

我执行了

FI  = open("rara.txt",'rb')
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

cnt = 0
for line in FI:
    cnt += 1
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
    if cnt==4:
        break
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'


lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell()
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

for line in FI:
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'

结果是

'1AA\r\n'   len==5  FI.tell() after FI.readline() :  5 

cnt==1   '2BB\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==2   '3CC\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==3   '4DD\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==4   '5EE\r\n'   len==5  FI.tell() after 'line in FI' :  75

FI.tell() after iteration 'for line in FI' :  75 


Traceback (most recent call last):
  File "E:\Python\NNN codes\esssssai.py", line 16, in <module>
    lineR = FI.readline()
ValueError: Mixing iteration and read methods would lose data

奇怪的是,如果我们通过 tell()更新“光标”,方法 readline()可以在迭代后再次激活(我不是知道什么是“光标”更新的幕后机制:

FI  = open("rara.txt",'rb')
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

cnt = 0
for line in FI:
    cnt += 1
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
    if cnt==4:
        pos = FI.tell()
        break
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'

FI.seek(pos)

lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell()
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

for line in FI:
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'

结果

'1AA\r\n'   len==5  FI.tell() after FI.readline() :  5 

cnt==1   '2BB\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==2   '3CC\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==3   '4DD\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==4   '5EE\r\n'   len==5  FI.tell() after 'line in FI' :  75

FI.tell() after iteration 'for line in FI' :  75 

''   len==0  FI.tell() after FI.readline() :  75
''   len==0  FI.tell() after FI.readline() :  75 


FI.tell() after iteration 'for line in FI' :  75 

无论如何,我们注意到即使算法在迭代期间只读取4行(感谢计数 cnt ),光标也会从文件的最开始就到达文件的末尾。迭代:迭代开始时在当前位置之前的所有文件都被读取。

所以 pos = FI.tell()在中断之前没有给出4行读取后的位置,而是文件末尾的位置。


如果我们想要在迭代之后再次 readline(),那么我们必须做一些特别的事情,从迭代期间读取的4行结束的确切点开始:

FI  = open("rara.txt",'rb')
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

cnt = 0
pos = FI.tell()
for line in FI:
    cnt += 1
    pos += len(line)
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
    if cnt==4:
        break
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell()
print "    pos   after iteration 'for line in FI' : ",pos,'\n'

FI.seek(pos)

lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell()
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

cnt = 0
for line in FI:
    cnt += 1
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'

结果

'1AA\r\n'   len==5  FI.tell() after FI.readline() :  5 

cnt==1   '2BB\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==2   '3CC\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==3   '4DD\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==4   '5EE\r\n'   len==5  FI.tell() after 'line in FI' :  75

FI.tell() after iteration 'for line in FI' :  75
    pos   after iteration 'for line in FI' :  25 

'6FF\r\n'   len==5  FI.tell() after FI.readline() :  30
'7GG\r\n'   len==5  FI.tell() after FI.readline() :  35 

cnt==1   '8HH\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==2   '9II\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==3   '10j\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==4   '11k\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==5   '12l\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==6   '13m\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==7   '14n\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==8   '15o\r\n'   len==5  FI.tell() after 'line in FI' :  75

FI.tell() after iteration 'for line in FI' :  75 

所有这些操作都是可能的,因为文件是以二进制模式打开的,因为我在Windows上使用'\ r \ n'作为行尾来写一个文件,即使它被命令写入(在' w'模式)类似'abcdef \ n',

而另一方面,Python转换(在模式'r'中)'\ n'中的所有'\ r \ n'。

这是一团糟,要控制所有这些,如果我们想要进行精确的操作,必须在'rb'中打开文件。


你知道吗?我喜欢这些游戏的文件位置