为什么用r+模式混合读写操作时效果不如预期,而用rb+时却能按预期工作?

编程语言 2026-07-09

正如 在这个相关问题中所解释的,读取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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章