Python 文件操作

真正有用的程序几乎都要和文件打交道——读配置、写日志、处理数据、保存结果。Python 的文件操作极其简洁,这一章把读写、路径处理、CSV/JSON、目录操作全讲透。

1. 打开文件:open

# open(文件名, 模式) 打开文件,返回文件对象
# 模式:r 读(默认)、w 写(覆盖)、a 追加、b 二进制、+ 读写

# 1. 写文件(w 模式:文件不存在则创建,存在则覆盖)
f = open("hello.txt", "w", encoding="utf-8")
f.write("第一行\n")
f.write("第二行\n")
f.close()              # ⚠ 必须手动关闭!不关会泄漏资源

# 2. 读文件(r 模式)
f = open("hello.txt", "r", encoding="utf-8")
content = f.read()     # 一次性读完
print(content)
f.close()
# 输出:
# 第一行
# 第二行

务必加 encoding="utf-8":Windows 默认编码是 GBK,不加这行读中文文件会乱码或报 UnicodeDecodeError。这是新手最常踩的坑。

2. with 语句:自动关闭(标准写法)

# with 语句:自动关闭文件,即使中间出错也不会忘记
# 这是 Python 文件操作的标准写法

# 写文件
with open("note.txt", "w", encoding="utf-8") as f:
    f.write("学习 Python\n")
    f.write("文件操作很重要\n")
    # with 块结束,文件自动关闭

# 读文件
with open("note.txt", "r", encoding="utf-8") as f:
    content = f.read()
print(content)

# 强烈推荐:任何文件操作都用 with,不要用 open + close
# 这避免了"忘记 close"或"中间抛异常导致文件未关"的资源泄漏问题

这是 Python 文件操作的事实标准,任何文件操作都该用 with,不要手动 open/close。原因:

3. 读取文件的几种方式

# 多种读取方式

# 1. read():一次性读取整个文件(小文件用)
with open("note.txt", "r", encoding="utf-8") as f:
    print(f.read())

# 2. readline():每次读一行
with open("note.txt", "r", encoding="utf-8") as f:
    line1 = f.readline()
    line2 = f.readline()
    print(line1, line2)

# 3. readlines():读取所有行,返回列表(每行一个元素)
with open("note.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()
print(lines)      # ['学习 Python\n', '文件操作很重要\n']

# 4. ⭐ 最佳实践:直接 for 循环逐行读(内存友好,大文件用)
with open("note.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line.strip())     # strip() 去掉末尾换行符

读大文件首选 for 循环逐行读(第 4 种方式)。f.read() 会把整个文件加载进内存,处理几 GB 的大文件会爆内存;逐行读只占一行内存。

4. 写文件:w 与 a 模式

# 写文件的几种方式

# w 模式:覆盖(原文件被清空!)
with open("log.txt", "w", encoding="utf-8") as f:
    f.write("覆盖写\n")

# a 模式:追加(在文件末尾添加)
with open("log.txt", "a", encoding="utf-8") as f:
    f.write("追加一行\n")
    f.write("再追加一行\n")

# writelines():写入一个列表(每个元素一行,但不会自动加换行符)
lines = ["苹果\n", "香蕉\n", "橘子\n"]
with open("fruits.txt", "w", encoding="utf-8") as f:
    f.writelines(lines)

# print() 也能写文件(用 file 参数)
with open("greeting.txt", "w", encoding="utf-8") as f:
    print("Hello", file=f)
    print("World", file=f)

w(覆盖)和 a(追加)的区别要记牢:用错模式会清空重要文件。建议不确定时用 x 模式(文件已存在会报错,防覆盖)。

5. 文件打开模式速查

# 文件打开模式速查
# r     读(默认)。文件不存在会报错 FileNotFoundError
# w     写。文件不存在则创建,存在则清空
# a     追加。文件不存在则创建,存在则末尾追加
# x     独占创建。文件已存在则报错(防止覆盖)
# b     二进制模式(配合上面用:rb/wb/ab)。处理图片/视频/压缩包
# t     文本模式(默认,通常不写)
# +     更新模式(可读可写:r+/w+/a+)

# 二进制读写(图片、视频、压缩包等)
with open("photo.jpg", "rb") as f:        # rb 读二进制
    data = f.read()

with open("copy.jpg", "wb") as f:         # wb 写二进制
    f.write(data)

6. pathlib:现代路径处理(推荐)

pathlib 是 Python 3.4+ 的现代路径库,比传统的 os.path 优雅得多——能用 / 拼接路径,方法更直观。

# pathlib:现代路径处理(推荐,比 os.path 优雅)
from pathlib import Path

# 当前目录
p = Path(".")
print(p.absolute())           # 当前目录的绝对路径

# 创建路径对象(用 / 拼接,Python 重载了运算符!)
file_path = Path("data") / "users" / "users.json"
print(file_path)              # data/users/users.json

# 常用操作
p = Path("data/users/users.json")
print(p.name)                 # users.json   文件名(含扩展名)
print(p.stem)                 # users        文件名(不含扩展名)
print(p.suffix)               # .json        扩展名
print(p.parent)               # data/users   父目录
print(p.exists())             # False/True   是否存在
print(p.is_file())            # 是否是文件
print(p.is_dir())             # 是否是目录

# 创建目录
Path("test_dir").mkdir(exist_ok=True)    # 已存在不报错

# 列出目录下的所有文件
for child in Path(".").iterdir():
    print(child)

# 用 glob 模式查找
for py_file in Path(".").glob("*.py"):
    print(py_file)

7. CSV 文件读写

CSV 是数据交换最常用的格式,Python 自带 csv 模块。

# CSV 文件处理(自带 csv 模块)
import csv

# 写 CSV
users = [
    ["姓名", "年龄", "城市"],
    ["小明", 20, "北京"],
    ["小红", 22, "上海"],
    ["小刚", 25, "广州"],
]
with open("users.csv", "w", encoding="utf-8-sig", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(users)         # 写多行

# 注意:
# - utf-8-sig:让 Excel 正确识别 UTF-8(中文不乱码)
# - newline="":避免 Windows 上多出空行

# 读 CSV
with open("users.csv", "r", encoding="utf-8-sig") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)
# 输出:
# ['姓名', '年龄', '城市']
# ['小明', '20', '北京']
# ...

# DictReader:把每行读成字典(用表头作 key)
with open("users.csv", "r", encoding="utf-8-sig") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["姓名"], row["年龄"])

几个坑点:utf-8-sig 让 Excel 正确识别中文(否则乱码);newline="" 避免 Windows 上多出空行。

8. JSON 文件读写

import json

# 写 JSON 文件
user = {"name": "小明", "age": 20, "hobbies": ["读书", "编程"]}
with open("user.json", "w", encoding="utf-8") as f:
    json.dump(user, f, ensure_ascii=False, indent=2)

# 读 JSON 文件
with open("user.json", "r", encoding="utf-8") as f:
    data = json.load(f)
print(data["name"])          # 小明
print(data["hobbies"][0])   # 读书

配置文件、API 数据持久化、缓存,JSON 是首选格式。ensure_ascii=False 让中文正常显示。

9. os 模块:目录与文件操作

# os 模块:文件和目录操作
import os

# 当前工作目录
print(os.getcwd())                # /Users/yourname/project

# 改变工作目录
# os.chdir("/tmp")

# 列出目录内容
print(os.listdir("."))            # ['hello.txt', 'note.txt', ...]

# 创建/删除目录
os.makedirs("a/b/c", exist_ok=True)   # 递归创建
# os.rmdir("a/b/c")                     # 删空目录
# os.removedirs("a/b/c")                # 递归删空目录

# 文件重命名/移动
# os.rename("old.txt", "new.txt")

# 删除文件
# os.remove("hello.txt")

# 路径相关(老式写法,推荐用 pathlib 替代)
print(os.path.join("a", "b", "c.txt"))   # a/b/c.txt
print(os.path.exists("hello.txt"))       # True
print(os.path.isfile("hello.txt"))       # True
print(os.path.isdir("."))                # True
print(os.path.basename("/a/b/c.txt"))    # c.txt
print(os.path.dirname("/a/b/c.txt"))     # /a/b

10. 编码问题排查

遇到 UnicodeDecodeError 或乱码,99% 是编码不一致。排查思路:

小结

文件操作是真实程序的基础。重点掌握:openwith 语句(标准写法)逐行读大文件w/a 模式区别pathlib 路径处理CSV/JSON 读写encoding="utf-8"。下一篇看异常处理——让程序健壮地处理意外。

← 上一篇 Python 类与面向对象

下一篇 Python 异常处理

✈️💬