我试图理解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
。
我正在阅读此处的文档,但我没有看到它在哪里解释了我观察到的行为。
看起来,无论大小如何,第一次读取都会查找文件末尾。
任何人都可以提供文档中解释这一点的链接吗?
我尝试在此网站上搜索类似的问题,但是虽然有很多与阅读相关的问题,但我发现没有一个提到这种行为。
更新
经过更多探索后,发现不是第一次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```
考虑这个例子:
您可能期望打印:
相反,它打印:
并且该文件包含
'HelloEmptyWorld'
执行后。即使这段代码:
按预期工作并打印:
因此,
.read()
不会将指针定位在文件末尾,否则第二个打印语句应该会导致错误或显示为空。但是,请考虑这个例子:
如果你执行这段代码,然后查看该文件,你会发现在位置8193处,写入了“World”一词。
因此,Python 似乎以 8192 字节或字符块的形式读取文本数据,尽管连续调用跟踪
.read()
读取缓冲区中的位置,但调用.write()
将使用实际的文件指针,该指针已向前移动 8k(或移动到末尾)文件的内容,以先到者为准)。无论是字符还是字节,您可以从中看出:
现在,文件中的字符大小为 2 个字节,单词“world”写入位置 4097(以字符为单位,但仍在字节 8192 之后),因此缓冲区大小以字节为单位。
(请注意,8192 和 4096 是 2 的幂,以防这些数字看起来任意;还要注意,第一个大文件的大小正好是 100000 字节,正如预期的那样,但第二个大文件的大小是 200002 字节,这导致
'World'
世界由于选择的编码和字节顺序标记,会稍微偏移一点)编辑,更多信息:
考虑一下:
输出:
这表明
.read()
在 a 之后.write()
、刷新缓冲区之前执行 a 可能会导致非常意外的结果。您会发现它将test2.txt
按照yyyyy
预期在开始时写入,但test1.txt
会在第一个读取缓冲区之后写入。我不确定这实际上是否不应该被视为 Python 中的错误......