(二)打开方式、读写位置与关闭
1. open 返回文件对象
Path.open(...) 与内置 open(path, ...) 都可以取得文件对象。上一章已经写过 with 的进入与退出,这里让真实文件完成同样的过程:
# w 打开时建立或清空文件;a 在末尾追加;r 从头读取。
from pathlib import Path
folder = Path("data")
folder.mkdir(exist_ok=True)
path = folder / "minutes.txt"
with path.open("w", encoding="utf-8") as stream:
stream.write("20\n")
with path.open("a", encoding="utf-8") as stream:
stream.write("35\n")
with path.open("r", encoding="utf-8") as stream:
print(repr(stream.read()))
print(repr(stream.read()))
print(stream.closed)输出 '20\n35\n'、''、True。文件对象保存这次读取的位置,第一次 read() 已经到达末尾,第二次得到空字符串;退出 with 后文件关闭,名称 stream 仍在,但不能再从这份已关闭的文件对象读取。
| 模式 | 打开时与写入时发生的动作 |
|---|---|
r |
读取现有文件,文件不存在时报 FileNotFoundError |
w |
创建文件;目标已有内容在打开时就清空 |
a |
创建或打开文件,写入追加到末尾 |
x |
新建文件,已有同名文件时报 FileExistsError |
b |
使用字节数据,例如 rb、wb |
+ |
同时允许读和写,例如 r+b,仍要跟踪当前读写位置 |
write(text) 不自动加换行,也不会像 print 那样插入分隔空格。文本模式返回写入的字符数,二进制模式返回字节数;真正放进文件的字节还取决于编码与换行处理。
2. 覆盖发生在当前位置
“可读可写”不表示在任意位置插入内容。先用二进制文件观察明确的字节偏移:
# r+b 从现有文件读写;seek 的偏移在这个二进制例子中按字节计。
from pathlib import Path
path = Path("positions.bin")
path.write_bytes(b"ABCDE")
with path.open("r+b") as stream:
stream.seek(1)
stream.write(b"xy")
stream.seek(0)
print(stream.read())得到 b'AxyDE'。从偏移 1 开始的两个字节被覆盖,原来的 B、C 消失,后面的 D、E 没有被自动后移。需要重写结构化记录时,通常先形成完整的新内容,再替换保存的文件。