第2章 2.1 fs 文件系统模块
🎯 开场:为什么你迟早要学这个?
想象一下这个场景:你是班里的学习委员,每天要整理同学们提交上来的作业。人工一个一个打开、复制、粘贴、重命名……50 个人的作业,光整理就要半小时,手指都快抽筋了。
如果有一个脚本,帮你自动把文件夹里所有的 .txt 文件读取出来,统计字数,然后按学号排序输出到一个汇总表……你省下的时间可以多打三把游戏。
这就是今天要学的——用代码操作文件。
你可能之前写过「Hello World」,,但那只是屏幕上的文字。真正的程序得能读写硬盘上的文件,才能做出有用的小工具。学了这一章,你就能:
- 自动读取一堆文件,做批量处理
- 把程序的结果保存下来,下次继续用
- 做一个自己的「待办清单」程序,数据永不丢失
说白了:学了这个,你的程序才从「一次性工具」变成「能长期使用的真正软件」。
🧱 基础:文件操作,其实就像管理你的书架
2.1.1 先搞清楚「路径」是什么
你家书架上有一本书,你知道它在哪排哪格,这叫「路径」。
Python 里也一样,文件在电脑里的位置叫路径,有两种写法:
# 绝对路径:从硬盘根目录开始算(C 盘、D 盘)
# Windows 用户
file_path = "C:\\Users\\apple\\Documents\\homework.txt"
# Mac / Linux 用户
file_path = "/Users/apple/Documents/homework.txt"
# 相对路径:从当前程序所在位置开始算(推荐用这个!)
file_path = "./data/homework.txt"
"./"意思是「当前文件夹」,"./data/"意思是「当前文件夹里的 data 文件夹」
2.1.2 读取文件——把书从书架上拿下来看
Python 读取文件,分三步走:开门 → 看书 → 关门。
# 第一步:打开文件(指定 "r" 表示读模式)
file = open("test.txt", "r", encoding="utf-8")
# 第二步:读取内容
content = file.read()
# 第三步:关闭文件(重要!不关会内存泄漏)
file.close()
print(content)
⚠️ 但是! 这样写有个坑——如果读取过程中报错,close() 就不会执行。所以正确姿势是用 with 语句,自动帮你关门:
with open("test.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
# with 块结束自动关闭文件,不用你操心
类比:with 就像自助餐厅的门,你进去它自动开,你出来它自动关。你不需要记得喊「关门」,系统替你搞定。
2.1.3 写入文件——把东西塞进书架
content = "这是我的第一行文字\n第二行内容"
with open("output.txt", "w", encoding="utf-8") as file:
file.write(content)
print("写入完成!")
注意:
"w"模式会清空文件再写入(相当于把书架清空重新放书)。如果想追加内容,用"a"模式(append):
with open("output.txt", "a", encoding="utf-8") as file:
file.write("\n这是追加的第三行")
2.1.4 按行读取——一行一行处理
一次性读取全部适合小文件。如果文件有 10000 行,你需要逐行处理:
with open("scores.csv", "r", encoding="utf-8") as file:
for line in file: # 每次循环读一行
line = line.strip() # 去掉换行符
if line: # 跳过空行
print(f"读到: {line}")
类比:这就像你整理书架,不是把书全扒下来堆成一堆,而是一本一本按顺序处理。
2.1.5 读写 JSON 文件——结构化数据的好帮手
JSON 就像一个有结构的「收纳盒」,能存复杂的数据(列表、字典嵌套)。
import json
# 写入 JSON
data = {
"name": "小明",
"age": 16,
"hobbies": ["篮球", "音乐", "编程"]
}
with open("user.json", "w", encoding="utf-8") as file:
json.dump(data, file, ensure_ascii=False, indent=2)
# 读取 JSON
with open("user.json", "r", encoding="utf-8") as file:
loaded_data = json.load(file)
print(loaded_data["name"]) # 输出: 小明
print(loaded_data["hobbies"]) # 输出: ['篮球', '音乐', '编程']
ensure_ascii=False让中文正常显示,indent=2让格式美观(不写就是一行压缩的)

2.1.6 文件是否存在——出门前先检查
import os
# 检查文件是否存在
if os.path.exists("config.json"):
print("配置文件存在,读取中...")
with open("config.json", "r") as f:
config = json.load(f)
else:
print("配置文件不存在,创建默认配置...")
config = {"theme": "light", "language": "zh"}
with open("config.json", "w") as f:
json.dump(config, f)
类比:就像你出门前看一眼天气预报,先判断要不要带伞。
🔥 实战:三个小项目,从入门到能跑
项目 1:单词统计小工具(5 分钟)
场景:老师让你统计一篇文章有多少个单词。
# word_counter.py
text = """
Python 是一门易学易用的编程语言
它的语法简洁优雅 适合初学者入门
学完基础语法后 你可以写出自己的小工具
"""
# 清洗数据:去掉换行符,转小写,分割成单词
words = text.replace("\n", " ").lower().split()
# 统计
word_count = len(words)
print(f"文章单词数:{word_count}")
# 找出最常见的单词
from collections import Counter
word_freq = Counter(words)
most_common = word_freq.most_common(3)
print(f"最常见的 3 个词:{most_common}")
预期输出:
文章单词数:24
最常见的 3 个词:[('适合', 1), ('初学者', 1), ('入门', 1)]
解释:所有词都只出现 1 次,说明这篇文章词汇很丰富!
项目 2:批量处理成绩单 CSV(15 分钟)
场景:班里有 5 个同学的语文成绩在 scores.csv 里,你要找出最高分和最低分。
首先创建 scores.csv:
name,chinese,math,english
小明,85,92,88
小红,90,87,95
小刚,78,95,82
小美,92,88,91
小强,83,90,89
# process_scores.py
import csv
# 读取 CSV
with open("scores.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f) # 把每行变成字典
students = list(reader)
# 把字符串转成数字
for student in students:
student["chinese"] = int(student["chinese"])
student["math"] = int(student["math"])
student["english"] = int(student["english"])
# 计算语文平均分
chinese_scores = [s["chinese"] for s in students]
avg_chinese = sum(chinese_scores) / len(chinese_scores)
# 找最高分和最低分
highest = max(students, key=lambda x: x["chinese"])
lowest = min(students, key=lambda x: x["chinese"])
print(f"语文平均分:{avg_chinese:.1f}")
print(f"最高分:{highest['name']},{highest['chinese']}分")
print(f"最低分:{lowest['name']},{lowest['chinese']}分")
# 把结果保存到新文件
with open("result.txt", "w", encoding="utf-8") as f:
f.write(f"语文成绩分析报告\n")
f.write(f"平均分:{avg_chinese:.1f}\n")
f.write(f"最高分:{highest['name']} {highest['chinese']}分\n")
f.write(f"最低分:{lowest['name']} {lowest['chinese']}分\n")
print("结果已保存到 result.txt")
预期输出:
语文平均分:85.6
最高分:小美,92分
最低分:小刚,78分
结果已保存到 result.txt
解释:用
csv.DictReader读取 CSV,每行自动变成字典,列名就是 key,方便又好读。

项目 3:你的第一个「待办清单」程序(15 分钟)
场景:做一个命令行待办清单,添加任务、查看列表、删除任务,数据存在文件里不会丢。
# todo_list.py
import json
import os
TODO_FILE = "todos.json"
# 读取待办列表(如果文件不存在就返回空列表)
def load_todos():
if os.path.exists(TODO_FILE):
with open(TODO_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return []
# 保存待办列表
def save_todos(todos):
with open(TODO_FILE, "w", encoding="utf-8") as f:
json.dump(todos, f, ensure_ascii=False, indent=2)
# 显示所有待办
def show_todos(todos):
if not todos:
print("📝 待办列表是空的,快去添加任务吧!")
return
print("=" * 30)
print("📋 你的待办清单:")
for i, todo in enumerate(todos, 1):
status = "✅" if todo["done"] else "⬜"
print(f" {i}. {status} {todo['task']}")
print("=" * 30)
# 添加任务
def add_todo(todos, task):
todos.append({"task": task, "done": False})
save_todos(todos)
print(f"✅ 已添加:「{task}」")
# 删除任务
def delete_todo(todos, index):
if 1 <= index <= len(todos):
removed = todos.pop(index - 1)
save_todos(todos)
print(f"🗑️ 已删除:「{removed['task']}」")
else:
print("❌ 无效的序号")
# 切换完成状态
def toggle_todo(todos, index):
if 1 <= index <= len(todos):
todos[index - 1]["done"] = not todos[index - 1]["done"]
save_todos(todos)
status = "完成" if todos[index - 1]["done"] else "未完成"
print(f"📌 「{todos[index - 1]['task']}」标记为{status}")
else:
print("❌ 无效的序号")
# 主程序
def main():
todos = load_todos()
print("🎯 欢迎使用待办清单!")
while True:
print("\n请选择操作:")
print("1. 查看清单")
print("2. 添加任务")
print("3. 删除任务")
print("4. 切换完成状态")
print("5. 退出")
choice = input("请输入数字(1-5):").strip()
if choice == "1":
show_todos(todos)
elif choice == "2":
task = input("请输入任务内容:").strip()
if task:
add_todo(todos, task)
elif choice == "3":
show_todos(todos)
index = input("请输入要删除的序号:")
if index.isdigit():
delete_todo(todos, int(index))
elif choice == "4":
show_todos(todos)
index = input("请输入要切换的序号:")
if index.isdigit():
toggle_todo(todos, int(index))
elif choice == "5":
print("👋 再见!记得完成任务哦~")
break
else:
print("❌ 无效选择,请输入 1-5")
if __name__ == "__main__":
main()
预期交互:
🎯 欢迎使用待办清单!
请选择操作:
1. 查看清单
2. 添加任务
3. 删除任务
4. 切换完成状态
5. 退出
请输入数字(1-5):2
请输入任务内容:写完 Python 作业
✅ 已添加:「写完 Python 作业」
解释:这个程序把数据存在
todos.json文件里,每次修改后自动保存。关闭程序再打开,数据还在。这就是文件持久化的威力!
💪 进阶:5 个新手必踩的坑 + 调试技巧
坑 1:忘记 encoding="utf-8",中文乱码
# ❌ 错误:没指定编码,Windows 默认用 GBK 读 UTF-8 文件会乱码
with open("test.txt", "r") as f:
content = f.read()
# ✅ 正确:显式指定 UTF-8
with open("test.txt", "r", encoding="utf-8") as f:
content = f.read()
坑 2:用 "w" 模式写入,把原文件内容覆盖了
# ❌ 错误:每次写入都清空文件
with open("log.txt", "w") as f:
f.write("第一条日志\n")
with open("log.txt", "w") as f:
f.write("第二条日志\n") # 第一条没了!
# ✅ 正确:追加模式 "a"
with open("log.txt", "a") as f:
f.write("第一条日志\n")
with open("log.txt", "a") as f:
f.write("第二条日志\n") # 两条都在
坑 3:路径写死,换台电脑就跑不通
# ❌ 错误:写死绝对路径,只在你电脑上能用
with open("C:\\Users\\apple\\data\\test.txt", "r") as f:
pass
# ✅ 正确:用相对路径,或者动态获取脚本所在目录
import os
script_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(script_dir, "data", "test.txt")
with open(file_path, "r", encoding="utf-8") as f:
pass
坑 4:文件读写前不检查是否存在
# ❌ 错误:文件不存在会报错 FileNotFoundError
with open("config.json", "r") as f:
config = json.load(f)
# ✅ 正确:先检查再读写
import os
if os.path.exists("config.json"):
with open("config.json", "r") as f:
config = json.load(f)
else:
config = {} # 默认配置
with open("config.json", "w") as f:
json.dump(config, f)
坑 5:读取大文件用 read() 一次性全读进来
# ❌ 错误:大文件(几 GB)会把内存撑爆
with open("huge_file.log", "r", encoding="utf-8") as f:
content = f.read() # 全部读进内存!
# ✅ 正确:分批读取或者用 readline()
with open("huge_file.log", "r", encoding="utf-8") as f:
for line in f: # 一行一行读,不占内存
if "ERROR" in line:
print(line.strip())
调试技巧:print 大法 + 日志
import logging
# 简单调试:print 打印关键变量
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
print(f"DEBUG: 读取到 {len(data)} 条数据") # 看看读没读到
# 正式项目:用 logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info("程序开始运行")
logger.warning("配置文件不存在,使用默认配置")
logger.error("无法连接到数据库")
✏️ 练习题
练习 1(2 分钟):单词统计升级
- 输入:把项目 1 的文本换成
"hello world hello python hello" - 预期输出:单词 "hello" 出现了 3 次
- 提示:用
text.count("hello")或用Counter统计
练习 2(3 分钟):给成绩判断加个 if
- 输入:在项目 2 里,如果小明的语文成绩 > 90,额外打印 "小明是语文小达人!"
- 预期输出:
小明是语文小达人! - 提示:在遍历 students 后,加一个 if 判断
练习 3(5 分钟):处理新的 CSV
- 输入:创建一个新的
products.csv:
name,price,stock
苹果,5,100
香蕉,3,50
橙子,8,30
- 预期输出:打印最贵的商品名称和价格
- 提示:参考项目 2 的
max(..., key=lambda x: x["price"])
练习 4(8 分钟):把两个项目串起来
- 输入:把练习 3 的 CSV 处理结果,保存到
report.txt文件里 - 预期输出:
report.txt文件包含「最贵商品:橙子,8元」 - 提示:参考项目 2 结尾的「保存到新文件」代码
练习 5(5 分钟):分析报错图
- 输入:运行以下代码,看报什么错:
with open("not_exist.txt", "r") as f:
print(f.read())
- 预期输出:分析为什么报错,以及怎么修复
- 提示:FileNotFoundError 表示文件不存在
作业:做一个「学生信息管理系统」
需求描述:做一个命令行程序,管理学生的姓名、年龄、三科成绩。
功能点:
1. 添加学生(姓名、年龄、语文/数学/英语成绩)
2. 查看所有学生列表
3. 查找单科最高分学生
4. 把学生数据保存到 students.json,程序重启后数据还在
加分项:
1. 支持删除学生
2. 支持按姓名搜索学生
验收标准:
- 能添加 3 个学生
- 能查看列表显示所有学生信息
- 关闭程序再打开,之前添加的学生还在
- 代码有注释,说明每个函数在干什么
提交方式:评论区贴代码或 GitHub 链接
📚 总结
这一章学了 3 个核心点:
1. 文件操作三步曲:打开 → 读写 → 关闭,用 with 语句自动管理
2. CSV/JSON 是最常用的数据格式,csv.DictReader 和 json.dump/load 要会用
3. 文件持久化是关键——程序重启数据不丢失,待办清单就是例子
延伸学习资源:
- 官方文档:Python 文件操作
- 书籍:《Python 编程:从入门到实践》第 8 章(文件和数据格式化)
- 视频:B 站「Python 文件操作 10 分钟入门」系列
互动钩子:你在学习或工作中有没有「手工处理文件累死了」的崩溃时刻?评论区说说你是怎么解决的,老粉优先回复!
📌 下章预告:学完文件读写,我们发现路径处理是个大问题——
"./data/../config.json"这种鬼画符到底指向哪?下一章我们来解决它。

评论(0)