我正在尝试理解Python中的文件IO,使用不同的打开模式,以及读取和写入同一文件对象(只是自学)。
我对以下代码感到惊讶(这只是我的探索):
with open('blah.txt', 'w') as f:
# create a file with 13 characters
f.write("hello, world!")
with open('blah.txt', 'r+') as f:
for i in range(5):
# write one character
f.write(str(i))
# then print current position and next 3 characters
print(f"{f.tell()}: ", f"{f.read(3)}")
with open('blah.txt', 'r') as f:
# look at how the file was modified
print(f.read())
哪个输出:
1: ell
14:
15:
16:
17:
0ello, world!1234
正如我所料,第一个字符被
0
覆盖,然后接下来读取的3个字符是ell
,但是我希望将1
写在o
中的hello
上,那么接下来的 3 个字符读作 , w
。
我正在阅读文档here,但我没有看到它在哪里解释了我观察到的行为。
看起来,无论大小如何,第一次读取都会查找文件末尾。
任何人都可以提供文档中解释这一点的链接吗?
我尝试在此网站上搜索类似的问题,但是虽然有很多与阅读相关的问题,但我发现没有一个提到这种行为。
更新
经过更多探索,并不是第一个
read
寻找文件末尾,而是第二次写入。同样,我不确定为什么,这就是为什么我希望在文档中找到解释这种行为的地方。
这是我对上面代码的更改,表明这不是第一次阅读:
with open('blah.txt', 'w') as f:
# create a file with 13 characters
f.write("hello, world!")
with open('blah.txt', 'r+') as f:
for i in range(3):
# write one character
f.write(str(i))
# then print current position and next 3 characters
print(f"{f.tell()}: ", f"{f.read(3)}")
print(f"{f.tell()}: ", f"{f.read(3)}")
with open('blah.txt', 'r') as f:
# look at how the file was modified
print(f.read())
哪个输出:
1: ell
4: o,
14:
14:
15:
15:
0ello, world!12```
考虑这个例子:
with open('test.txt', 'w') as f:
f.write('HelloEmpty')
with open('test.txt', 'r+') as f:
print(f.read(5))
print(f.write('World'))
f.flush()
f.seek(0)
print(f.read(10))
您可能希望打印:
Hello
5
HelloWorld
相反,它打印:
Hello
5
HelloEmpty
即使这段代码:
with open('test.txt', 'w') as f:
f.write('HelloEmpty')
with open('test.txt', 'r+') as f:
print(f.read(5))
print(f.read(5))
按预期工作并打印:
Hello
Empty
因此,
.read()
不会将指针定位在文件末尾,否则第二个打印语句应该会导致错误或出现空值。
但是,请考虑这个例子:
with open('test.txt', 'w') as f:
for _ in range(10000):
f.write('HelloEmpty')
with open('test.txt', 'r+') as f:
print(f.read(5))
print(f.write('World'))
如果你执行这段代码,然后查看该文件,你会发现在位置8193处,写入了“World”一词。
因此,Python 似乎以 8192 字节或字符块的形式读取文本数据,尽管对
.read()
的连续调用跟踪读取缓冲区中的位置,但对 .write()
的调用将使用已移动的实际文件指针提前 8k(或到文件末尾,以先到者为准)。
无论是字符还是字节,从这里就可以看出:
with open('test.txt', 'w', encoding='utf16') as f:
for _ in range(10000):
f.write('HelloEmpty')
with open('test.txt', 'r+', encoding='utf16') as f:
print(f.read(5))
print(f.write('World'))
现在,文件中的字符大小为 2 个字节,单词“world”写入位置 4097,因此缓冲区大小以字节为单位。
(请注意,8192 和 4096 是 2 的幂,以防这些数字看起来任意)