AI 学院 · Python 入门线 · 节点 ④ / ⑨

文件与异常

手把手教程:让程序读写磁盘、在出错时不崩溃、用 JSON 与别的程序交换数据。约 5-7 个番茄,学完做出一个「成绩存档」程序才算过。

状态 进行中 前置 ③ 函数与模块 下一步 ⑤ 面向对象入门

第 0 步 · 程序为什么会"忘记"

到目前为止,你写的程序一退出,数据就没了(变量在内存里)。文件 = 磁盘上的持久存储。学会读写文件,程序才真正"办事":日志、配置、数据存档、批处理……

第 1 步 · 读文件

1.1 最基础写法(三步:打开→读→关闭)

f = open("data.txt", "r")   # r = read 只读模式
content = f.read()            # 整个文件读成一个字符串
f.close()                   # 关闭(忘了关会占用句柄)

1.2 推荐写法:with 自动关闭(永远用这个)

with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()     # with 块结束自动 close,不怕忘
# 读成行列表:
with open("data.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()   # ['第一行\n', '第二行\n', ...]
encoding="utf-8" 必须养成习惯:Windows 默认用 gbk 读文件,中文字符会乱码或报 UnicodeDecodeError。写上 utf-8 到处都能跑。

第 2 步 · 写文件

with open("out.txt", "w", encoding="utf-8") as f:
    f.write("第一行\n")       # \n 是换行符
    f.write("第二行\n")

# 追加模式(不清空原内容)
with open("log.txt", "a", encoding="utf-8") as f:
    f.write("2026-08-12 新纪录\n")
模式速查"r" 读(文件不存在 → FileNotFoundError);"w" 写(存在则清空重写!);"a" 追加;"x" 新建(已存在报错,防覆盖)。

第 3 步 · 异常处理(try/except)

文件会不存在、用户会输错、网络会断。异常处理 = 给程序穿防弹衣。

3.1 基本结构

try:
    with open("no_such.txt", "r") as f:
        content = f.read()
except FileNotFoundError:
    print("文件不存在,先创建它")
except Exception as e:      # 兜底:任何异常都接住
    print("出错了:", e)

3.2 完整结构:try / except / else / finally

try:
    num = int(input("数字:"))
except ValueError:
    print("这不是数字")
else:
    print(f"你输入了 {num}")   # 没异常才执行
finally:
    print("无论如何都会执行")   # 清理资源用
别用裸 except: 什么都不写会吞掉所有错误(包括你没想到的),难排查。精确捕获(ValueError、FileNotFoundError…)才是专业做法;兜底用 except Exception 并打印信息。

第 4 步 · JSON(程序间的通用语言)

JSON 是 Web/API/配置的事实标准格式,长得像 Python 字典:

4.1 写入(dump)

import json

student = {"name": "丢丢", "age": 6, "scores": {"数学": 92, "英语": 88}}

with open("student.json", "w", encoding="utf-8") as f:
    json.dump(student, f, ensure_ascii=False, indent=2)
    # ensure_ascii=False:中文原样保存(否则变成 \uXXXX)

4.2 读取(load)

with open("student.json", "r", encoding="utf-8") as f:
    data = json.load(f)
print(data["name"], data["scores"]["数学"])   # 丢丢 92
JSON 与字典的区别:JSON 是文本(文件里是字符串);Python 字典是内存对象dump/load 负责在两者间转换。以后调 API(⑧)返回的就是 JSON 文本。

第 5 步 · 路径(文件在哪里)

import os

os.getcwd()                # 当前工作目录
os.path.exists("data.txt")  # True/False 文件是否存在
os.path.join("data", "raw", "a.txt")  # 跨平台拼路径
os.makedirs("data/raw", exist_ok=True)  # 建目录(存在也不报错)
路径口诀:相对路径是"从程序当前目录出发";写脚本时用 os.path.join 而不是手拼 "data/raw"(Windows 用反斜杠会炸)。更现代的 pathlib 节点 ⑥ 再学。

第 6 步 · 实战项目:成绩存档程序

需求:一个命令行程序——输入学生与多科成绩,可保存、可查看、可追加,数据用 JSON 持久化。这就是"最小可用的数据管理程序"。

Step 1:核心函数库(保存 + 读取 + 加成绩)

# grade_book.py
import json, os

FILE = "grades.json"

def load_grades():
    """读取成绩,文件不存在返回空字典"""
    if not os.path.exists(FILE):
        return {}
    with open(FILE, "r", encoding="utf-8") as f:
        return json.load(f)

def save_grades(grades):
    with open(FILE, "w", encoding="utf-8") as f:
        json.dump(grades, f, ensure_ascii=False, indent=2)

Step 2:主程序(命令循环 + 异常兜底)

# main.py
import grade_book

grades = grade_book.load_grades()

while True:
    cmd = input("命令(add/see/quit):").strip().lower()
    if cmd == "quit":
        break
    elif cmd == "add":
        name = input("学生名:")
        subject = input("科目:")
        try:
            score = float(input("分数:"))
        except ValueError:
            print("分数无效,未保存")
            continue
        grades.setdefault(name, {})[subject] = score
        grade_book.save_grades(grades)
        print("已保存")
    elif cmd == "see":
        for name, subs in grades.items():
            print(name, subs)
    else:
        print("未知命令")
这个程序的意义:它第一次实现了"数据进出磁盘"。以后任何项目(背单词、记账、番茄统计)都是这个骨架:数据结构 + 文件读写 + 命令循环。跑通它,你的脚本就能在服务器上长期运行了。

第 7 步 · 报错手册(本节点新增)

1. FileNotFoundError —— 读的文件不存在。修法:先 os.path.exists() 判断,或 try/except。
2. UnicodeDecodeError —— 文件编码不是 utf-8。修法:open 时指定 encoding="utf-8";老文件试 encoding="gbk"
3. json.JSONDecodeError —— JSON 文件内容损坏(比如手动编辑弄坏括号)。修法:备份后检查文件;读的时候 try/except 兜底。
4. PermissionError —— 没权限读写(文件被占用/目录只读)。修法:检查文件是否被别的程序打开、路径权限。

节点自测清单

全勾 → 节点 ④ 完成,进入节点 ⑤(面向对象入门)。未勾 → 回看对应步骤。

推荐资料