readline()
和 for line in file
一起使用是否安全,并且它们保证使用相同的文件位置?
通常,我想要忽略第一行(标题),所以我这样做:
FI = open("myfile.txt")
FI.readline() # disregard the first line
for line in FI:
my_process(line)
FI.close()
这样做安全吗,也就是说,在迭代行时保证使用相同的文件位置变量吗?
不,这并不安全:
由于使用了读取前瞻缓存(read-ahead buffer),将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
这在长期运行中很有效。它忽略了您正在处理文件的事实,并且适用于任何序列。此外,拥有显式迭代器对象(rdr
)保持不变,允许您在for循环体内跳过行而不会弄乱任何东西。
with open("myfile.txt","r") as source:
rdr= iter(source)
heading= next(rdr)
for line in rdr:
process( line )
如果机制得到控制,那么就是安全的。
=============================
.
在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
因此,在break之前的pos = FI.tell()并不是读取4行后的位置,而是文件末尾的位置。
.
如果我们想要在迭代过程中从读取4行的确切位置再次使用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
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' 模式下会将所有的 '\r\n' 转换为 '\n'。
这实在是一团糟,要想控制这一切,文件必须以 'rb' 模式打开,如果我们想要进行精确的操作的话。
.
你知道吗?我喜欢对文件位置进行这些游戏。
next
函数。 - SilentGhost.next
已经被移除了。 - SilentGhost.next()
的小问题一样。 - eyquem