Python 现代开发学习笔记

(二)打开方式、读写位置与关闭

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 没有被自动后移。需要重写结构化记录时,通常先形成完整的新内容,再替换保存的文件。

文件位置前进与覆盖两个字节的过程

笔记正文与全部题解 · Ctrl / ⌘ K