Python中read后write写入位置不符预期:是特性还是Bug?
为什么以r+模式读取文件后直接write会写入末尾而非当前指针位置?
问题背景
在Python 3.11.2版本(运行于Windows 10 Home 22H2及MacOS 12.6.3系统)中,以r+模式打开文件并读取到中间位置后,直接调用file.write()时,写入位置是文件末尾而非当前指针位置,这与read()从当前位置继续读取的行为不符。
测试环境与内容
初始文件内容
content.txt初始内容:
this is just some miscellaneous unimportant text
测试代码
with open("content.txt", "r+", encoding="utf-8") as file: print("start tell", file.tell()) a = file.read(20) a_tell = file.tell() print(f"{a=} {a_tell=}") b = file.read(5) b_tell = file.tell() print(f"{b=} {b_tell=}") file.write("ABCDE") abcde_tell = file.tell() print(f"{abcde_tell=}") file.seek(b_tell) print("seek b_tell", file.tell()) file.write("XYZ") xyz_tell = file.tell() print(f"{xyz_tell=}")
代码输出
start tell 0 a='this is just some mi' a_tell=20 b='scell' b_tell=25 abcde_tell=53 seek b_tell 25 xyz_tell=28
结果对比
- 预期文件内容:
this is just some miscellXYZDEs unimportant text - 实际文件内容:
this is just some miscellXYZous unimportant textABCDE
观察到的现象
file.read(n)后调用file.read(m)会从位置n开始读取,符合预期file.read(n)后直接调用file.write("ABCDE")会写入文件末尾而非位置n,不符合直觉- 调用
file.seek(n)后再执行file.write("XYZ")会在位置n写入,符合预期
原因分析
这是预期行为,并非Bug。Python的文件操作基于底层操作系统的C标准库实现,当在r+模式下混合读写操作时,遵循以下规则:
- 当从读操作切换到写操作时,如果没有先调用
seek()明确指定写入位置,操作系统会将文件指针移动到文件末尾再执行写入。这是因为读操作可能会在缓冲区留存未处理的数据,为了避免数据错乱,标准库强制将指针移至末尾,确保写入操作不会覆盖未读取的缓冲区内容。 - 同理,从写操作切换到读操作时,也需要先调用
seek()(除非是刚完成写入后立即读取,此时指针已在写入后的位置)。
在测试中,两次read()后指针停在位置25,但直接调用write()时,由于没有先执行seek(),系统自动将指针移到文件末尾(初始文件长度为48,写入5个字符后指针位置变为53),因此ABCDE被追加到了文件末尾。而调用seek(b_tell)明确指定位置后,写入操作就会在指定的位置25执行,覆盖原有内容。
解决方案
如果需要在读取后的当前指针位置写入,只需在write()前调用seek()将指针定位到当前位置即可,即使tell()显示指针已经在该位置:
# 在read()之后、write()之前添加 file.seek(file.tell()) file.write("ABCDE")
内容的提问来源于stack exchange,提问作者Katze2664
相关产品推荐
相关产品推荐

