与Python 2(2.7.15)不同,当二进制文件以追加和读取方式打开时,我发现在Python 3(3.6.5)中出现了奇怪的f.tell()行为。如果当前寻找位置不在文件末尾时写入n个字节,则以下几件事情似乎会按预期发生:
Python 3文档警告不要在文本文件上使用seek()/tell()(请参见io.TextIOBase),并且在某些平台上有一个关于追加模式的警告(请参见open()):
[...] 'a' for appending (which on some Unix systems, means that all writes append to the end of the file regardless of the current seek position).
但我正在使用二进制文件,写入似乎确实是追加到文件末尾而不考虑寻址位置,所以我的问题不同。
我的问题是:这种行为是否有记录(直接或间接),或者至少记录了该行为未指定?
编辑:
文本文件似乎没有这个问题(无论在Python 2还是3中),因此只有二进制文件不能按预期工作。
Python 3文档(io.TextIOBase)指出,对于文本文件,tell()返回一个“不透明”的值(即未指定该值如何表示位置),由于未提及此是否也适用于二进制文件,因此可能会认为我的问题与此不透明性有关。然而,这是不可能的,因为即使是不透明的值,在传递给seek()时,也必须将文件指针返回到调用tell()时的位置,在上面的示例中,当tell()在同一文件位置(文件结尾)返回6和12时,只有seek(12)才会将文件指针实际移动到该位置。因此,值6不能用文件指针不透明性来解释。
- 文件指针将移动到文件末尾。
- n个字节被写入。
- n被添加到文件指针中。
然而,似乎f.tell()没有注意到第1步,因此f.tell()返回的值相对于实际文件指针偏移了一个恒定的负值。我在Windows和Linux上都看到了相同的情况。
这是一些演示问题的Python 3代码:
import io
# Create file with some content
f = open('myfile', 'wb')
f.write(b'abc')
print(f.tell()) # 3
f.close()
# Now reopen file in append+read mode and check that appending works
f = open('myfile', 'a+b')
print(f.tell()) # 3
f.write(b'def') # (Append)
print(f.tell()) # 6
# Now seek to start of file and append again -> tell() gets out of sync!
print(f.seek(0)) # 0
print(f.tell()) # 0
f.write(b'ghi') # (Append)
print(f.tell()) # 3!!! (expected 9)
f.write(b'jkl') # (Append)
print(f.tell()) # 6!!! (expected 12)
# Try calling seek without moving file pointer -> tell() starts working again
print(f.seek(0, io.SEEK_CUR)) # 12 (correct)
print(f.tell()) # 12 (correct)
# Read whole file to verify its contents
print(f.seek(0)) # 0
print(f.read()) # b'abcdefghijkl' (correct)
f.close()
Python 3文档警告不要在文本文件上使用seek()/tell()(请参见io.TextIOBase),并且在某些平台上有一个关于追加模式的警告(请参见open()):
[...] 'a' for appending (which on some Unix systems, means that all writes append to the end of the file regardless of the current seek position).
但我正在使用二进制文件,写入似乎确实是追加到文件末尾而不考虑寻址位置,所以我的问题不同。
我的问题是:这种行为是否有记录(直接或间接),或者至少记录了该行为未指定?
编辑:
文本文件似乎没有这个问题(无论在Python 2还是3中),因此只有二进制文件不能按预期工作。
Python 3文档(io.TextIOBase)指出,对于文本文件,tell()返回一个“不透明”的值(即未指定该值如何表示位置),由于未提及此是否也适用于二进制文件,因此可能会认为我的问题与此不透明性有关。然而,这是不可能的,因为即使是不透明的值,在传递给seek()时,也必须将文件指针返回到调用tell()时的位置,在上面的示例中,当tell()在同一文件位置(文件结尾)返回6和12时,只有seek(12)才会将文件指针实际移动到该位置。因此,值6不能用文件指针不透明性来解释。
b''
,表明文件指针实际上已经到达文件末尾而不是位置3。 f.read()的一个副作用是f.tell()将重新开始工作,并为相同的位置报告9。 - Ovaflo