Menu

Python 文件操作:安全地读取、写入和追加文件

如何在 Python 中读写文件:with 语句、文本模式与二进制模式,以及更安全的现代路径 API。

文件不过是带路径的字符串

大多数程序迟早都要读写文件:配置、用户数据、日志、CSV 导出、小型缓存。Python 让这件事很简单:只需要一个内置函数 open(),再加一个 with 块确保文件被干净地关闭。

我们来逐一看看常见的情况。

读取整个文件

最简单的读取方式:

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

print(contents)

open("notes.txt") 以读取模式(默认模式)打开文件。with 块意味着离开这个块时 Python 会关闭文件,即使抛出了异常也一样。文件关闭后就不能再用 f 了,文本内容保存在 contents 中。

contents 是包含整个文件内容的一个字符串。小文件这样读没问题,2 GB 的日志就不行了。

逐行读取

对于较大的文件,应该逐行遍历,而不是把所有内容都读进内存:

with open("big.log") as f:
    for line in f:
        if "ERROR" in line:
            print(line.strip())

每次迭代得到一行,包括行末的换行符,所以 .strip() 才会出现得这么频繁。如果你想要一个由各行组成的列表,可以用 f.readlines(),不过通常直接遍历才是你想要的。

写入文件

要写入文件,把模式作为第二个参数传进去:

with open("output.txt", "w") as f:
    f.write("first line\n")
    f.write("second line\n")

有两点需要注意:

  • "w" 会覆盖文件。 如果 output.txt 已经存在,open 一运行,原来的内容就没了。
  • 换行符要自己加。 f.write("hello") 只会写入这五个字符,末尾没有换行。

如果要追加而不是覆盖:

with open("output.txt", "a") as f:
    f.write("another line\n")

也可以用 writelines 一次写入多行:

lines = ["a\n", "b\n", "c\n"]
with open("letters.txt", "w") as f:
    f.writelines(lines)

规则一样:换行符由你自己提供。

用 print 写入文件

print 有一个 file 参数,用它写文件就不用手动加换行符了:

with open("log.txt", "w") as f:
    print("started", file=f)
    print("finished", file=f)

每次 print 都会写入它的参数,再加上一个换行符。对于随手输出的内容,这往往是最顺手的写法。

文本模式与二进制模式

open 默认使用文本模式。Python 会把字节解码成字符串(在现代平台上默认用 UTF-8),并处理换行符的转换。

对于图片、PDF、编译后的文件,或者任何不是文本的内容,在模式中加上 "b",以二进制模式打开:

with open("image.png", "rb") as f:
    data = f.read()

print(len(data))  # number of bytes

with open("image_copy.png", "wb") as f:
    f.write(data)

在二进制模式下,你得到的是 bytes 对象而不是 str,Python 也不会改动行尾。

指定编码

对于文本文件,要明确写出编码。在 2026 年,UTF-8 几乎总是正确的选择:

with open("notes.txt", encoding="utf-8") as f:
    contents = f.read()

如果你处理的是来自只用 Windows 的老系统的旧文件,可能还会遇到 cp1252 或 latin-1。编码猜错了,就会得到乱码或者 UnicodeDecodeError。

pathlib:处理路径的现代方式

标准库的 pathlib 模块提供了比原始字符串更顺手的 API:

from pathlib import Path

path = Path("notes.txt")

# Simple read and write.
contents = path.read_text(encoding="utf-8")
path.write_text("new contents\n", encoding="utf-8")

# Build paths without worrying about / vs \.
data_dir = Path("data")
log_path = data_dir / "today.log"

print(log_path)
print(log_path.exists())
print(log_path.suffix)       # ".log"
print(log_path.stem)         # "today"
print(log_path.parent)       # "data"

当你只想一次性读写全部内容时,Path.read_text() 和 write_text() 是 with open(...) as f 写法的快捷方式。如果要逐行遍历,仍然要用 open 或 path.open()。

一个完整的小例子

从文件中读取一组条目,过滤后把结果写入另一个文件:

from pathlib import Path

source = Path("items.txt")
destination = Path("filtered.txt")

items = source.read_text().splitlines()
kept = [item for item in items if item and not item.startswith("#")]

destination.write_text("\n".join(kept) + "\n")

print(f"Kept {len(kept)} items out of {len(items)}")

splitlines() 是和 join 配套的按行操作方法。它按换行符拆分字符串,但不保留换行符。如果你之后反正要把各部分重新拼起来,它就很方便。

出错的时候

打开一个不存在的文件会抛出 FileNotFoundError。读取一个没有权限的文件会抛出 PermissionError。这两个都是 OSError 的子类,而 OSError 又是 Exception 的子类。我们会在下一页详细讲如何正确处理异常。

现在先简单预览一下错误处理的样子:

from pathlib import Path

path = Path("maybe.txt")

try:
    contents = path.read_text()
except FileNotFoundError:
    print("File doesn't exist - starting fresh.")
    contents = ""

print(repr(contents))

关键习惯

  • 始终用 with open(...),不要用原始的 open 再手动关闭。
  • 文本文件始终传入 encoding=,默认用 UTF-8。
  • 大文件逐行遍历,不要用 .read() 一次读完。
  • 处理路径和常见的读写操作时,用 pathlib,能帮你省去大量字符串拼接的麻烦。

常见问题

Python 中怎么读取文件?

把 open() 和 with 语句一起使用,用完后它会自动关闭文件。with open('file.txt') as f: contents = f.read() 会把整个文件读成一个字符串。如果要逐行读取,直接遍历文件对象:for line in f:。

打开模式 'r'、'w' 和 'a' 有什么区别?

'r' 是读取(默认模式)。'w' 是写入:文件不存在时创建它,存在时清空它。'a' 是追加:在文件末尾添加内容,不会删掉已有内容。加上 'b' 是二进制模式,加上 '+' 是读写模式。

为什么要用 with open 而不是直接用 open?

with 语句能保证即使中途出错,文件也会被关闭。不用 with 的话,你得自己调用 .close(),还要记得在出错的分支里也调用。with 更安全,代码也更少。

Coddy 编程语言插图

和 Coddy 一起学编程

开始