为什么用r+模式混合读写操作时效果不如预期,而用rb+时却能按预期工作?
正如 在这个相关问题中所解释的,读取Python中的文件会把数据加载到缓冲区,这意味着在你能够正确写入之前需要执行一个 seek 操作。
如果文件的内容是
Hi, I'm a text file!
I got a text file here.
并且你想在读取第一行后替换第二行,那么在写入之前你需要进行一个 seek:
import os
with open("test.txt", "r+") as f:
print(f.readline().strip())
print('Replacing bytes at position', f.tell())
f.seek(0, os.SEEK_CUR)
f.write('I had')
但如果我以二进制模式打开文件,似乎按预期工作,而且不需要 seek:
with open("test.txt", "rb+") as f:
print(f.readline().strip())
print('Replacing bytes at position', f.tell())
f.write(b'I had')
它真的按预期工作吗,还是迟早会遇到问题(也许是在更大规模的读取、写入或文件上)?为什么会起作用?
解决方案
这是根本上与基于对数据的感知而产生的缓冲行为的多变性有关……'rb+' 会把你带到你认为应该在的位置(也就是说tell() 不是在撒谎),'r+' 则不会(tell() 显示的是它真相的一个版本——见下方代码)……关于这点,可能有大量的技术讨论和抓头挠脑的情况。无论如何,基于你的帖子给出一个显示文本的实际位置与“声称”位置的简单示例应该会有帮助。我这点两分钱的看法——如果你要修改它,使用 'rb+' 会更少麻烦。
希望这对你有帮助。
cat rb.py
import os
def test():
print('\nbinary read/buffering\n')
with open('bin.txt','rb+') as X:
X.readline().strip()
print('replacing bytes at position:', X.tell())
X.write(b'I had')
X.flush()
print('\ntext read/buffering\n')
with open('text.txt','r+') as X:
X.readline().strip()
#
# here's the culprit !
print('real buffer position:', X.buffer.tell())
print('replacing bytes at text position:', X.tell())
X.seek(0,os.SEEK_CUR)
X.write('I had')
X.flush()
test()
$ cp orig.txt bin.txt ; cp orig.txt text.txt # seed file
$ cat orig.txt
Hi, I'm a text file!
I got a text file here
$
$ python3 rb.py #run the edits/updates
binary read/buffering
replacing bytes at position: 21
text read/buffering
real buffer position: 44 # actual file cursor position, that's why seek is needed
replacing bytes at text position: 21
$ #see the results
$ cat bin.txt:
Hi, I'm a text file!
I had a text file here
$ cat text.txt
Hi, I'm a text file!
I had a text file here
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。