2.27. 读写

文件存放在磁盘上;Python 通过 open() 访问它们,该函数返回一个文件对象,其方法用于读写底层的字节。

2.27.1. open 与模式

第一个参数是路径;第二个参数是模式 —— 一个简短的字符串,告诉 Python 这个文件将如何被使用:

  • "r" —— 读取(默认)。打开一个已存在的文件以供读取。

  • "w" —— 写入。创建一个新文件,或将一个已存在的文件截断为空。

  • "a" —— 追加。以在文件末尾写入的方式打开文件,且不截断。

  • 在上述任意模式后追加 "b""rb""wb""ab")—— 二进制模式。此时文件内容是 bytes 而非 str

f = open("notes.txt", "r")
text = f.read()
f.close()

2.27.2. 使用上下文管理器

如果 open()close 之间有任何代码抛出异常,上面的写法就会泄漏文件句柄。解决办法是使用 with 语句(参见 上下文管理器):

with open("notes.txt") as f:
    text = f.read()

# f is closed here, even if read() failed

这是标准写法 —— 每次都这样写。

2.27.3. 读取

文件对象支持几种读取方式:

  • io.IOBase.read() —— 读取整个文件(或 N 个字节)并将其作为单个字符串(或字节对象)返回。

  • io.IOBase.readline() —— 读取一行,包括末尾的 "\n"

  • 直接迭代文件会一次产出一行,其内存占用比一次性读取整个文件要小得多。

with open("log.txt") as f:
    for line in f:
        print(line.rstrip())

str.rstrip() 会在打印前移除末尾的换行符,这样输出就不会出现双倍行距。

2.27.4. 写入

"w" 模式打开文件,并使用 io.IOBase.write()

with open("out.txt", "w") as f:
    f.write("hello\n")
    f.write("world\n")

io.IOBase.write() 不会添加换行符 —— 它精确地写入你给它的字节(在文本模式下则是字符)。

2.27.5. 文本与二进制

文本模式(默认,即不带 "b""r" / "w")会使用默认编码把读入的字节解码为 str,并把写出的 str 编码回字节。用它来处理配置、日志、JSON —— 任何本身就是文本的内容。

二进制模式("rb" / "wb")会跳过解码步骤并返回 bytes。用它来处理图像、按结构打包的记录、网络抓包 —— 任何每个字节都至关重要且文件不可供人阅读的内容。

2.27.6. 列出与删除文件

os 模块暴露了那些不在文件对象本身上的文件系统操作:

import os

for name in os.listdir("/"):
    print(name)

当文件或目录可能不存在时,请在这些操作周围捕获 OSError —— 在实际脚本中,这类操作是异常常见的出现之处之一。