第7章 文件及其应用
7.1 文件基本知识

📖 本节导读
同学们,在前面的学习中,我们已经掌握了 Python 的基础语法、分支程序设计、循环程序设计、组合数据类型以及函数等重要知识。大家是否思考过一个问题:我们之前编写的所有程序,运行结束后数据都去哪里了?
答案是——数据消失了。因为程序运行时,数据存储在计算机的内存中,一旦程序结束运行,内存中的数据就会被释放。这就好比我们在课堂上用黑板写笔记,下课后黑板被擦干净了,笔记自然就没了。
那么,如果我们希望数据能够永久保存,即使关闭计算机也不会丢失,该怎么办呢?这就需要用到文件。文件是存储在计算机外部存储设备(如硬盘、U盘)上的数据集合,它可以让我们的数据长期保存、反复使用。
本章我们将学习: - 文件的基本概念和操作方式 - 文本文件的读写操作 - 文本文件的应用实例
💡 知识串联回忆: 在第2章”简单程序设计”中,我们学习了 input() 函数和 print() 函数来实现数据的输入和输出。但那种方式下,数据只能在程序运行时临时使用。而文件操作则让我们能够将数据持久化存储,这是程序设计中非常重要的能力。本节我们将从文件的基本概念出发,逐步学习如何使用 Python 来操作文件。

7.1.1 文件概述
一、文件的概念
1. 什么是文件
文件是存储在外部存储介质(如硬盘、U盘、光盘等)上的数据集合,它是操作系统管理数据的基本单位。每个文件都有一个唯一的文件名,操作系统通过文件名来识别和管理文件。
通俗地理解,文件就像是一个收纳盒,里面存放着各种数据。你可以给这个收纳盒贴上标签(文件名),以后需要用到里面的数据时,通过标签就能找到它。
2. 为什么需要文件
让我们通过一个具体的例子来理解文件的重要性。
【思考场景】 假设你是 CK 学校学生会的一名干事,负责管理全校同学的社团报名信息。如果只用我们之前学过的变量来存储数据,会面临什么问题呢?
# ===== 回忆:第2章学过的变量存储方式 =====# 存储几位同学的报名信息name1 = "张三"club1 = "Python编程社"name2 = "李四"club2 = "篮球社"name3 = "王五"club3 = "摄影社"# 使用列表存储(回忆第5章学过的列表)students = [ {"name": "张三", "club": "Python编程社"}, {"name": "李四", "club": "篮球社"}, {"name": "王五", "club": "摄影社"}]print("报名信息:", students)
报名信息: [{'name': '张三', 'club': 'Python编程社'}, {'name': '李四', 'club': '篮球社'}, {'name': '王五', 'club': '摄影社'}]
⚠️ 问题来了: 上面的程序运行结束后,所有数据都会从内存中消失。下次再运行程序时,数据又回到了初始状态。如果你录入了几百名同学的报名信息,程序一关,全部白费!
解决方案: 将数据保存到文件中。文件存储在硬盘上,即使关闭计算机,数据也不会丢失。下次运行程序时,只需要从文件中读取数据即可。
3. 内存与外存的区别
为了更好地理解文件的作用,我们需要区分两个重要的概念:
比较项 | 内存(RAM) | 外存(硬盘等) |
速度 | 非常快 | 相对较慢 |
容量 | 较小(通常8GB~32GB) | 较大(通常256GB~2TB) |
持久性 | 断电后数据丢失 | 断电后数据不丢失 |
价格 | 较贵 | 较便宜 |
用途 | 程序运行时临时存放数据 | 长期保存数据 |
💡 记忆技巧: 可以把内存比作课桌,外存比作书柜。课桌上的东西拿取方便但空间有限,下课后要清理;书柜虽然拿取稍慢,但空间大,东西可以长期存放。
4. 文件在程序中的角色
在我们的 Python 程序中,文件扮演着桥梁的角色:
程序(内存) ←→ 文件(外存)↑↑ 临时存储永久存储 运行时使用关机后仍在
通过文件,程序可以实现以下功能: - 数据持久化:将程序运行的结果保存下来,下次继续使用 - 数据共享:不同的程序可以通过读写同一个文件来交换数据 - 数据备份:将重要数据保存到文件中,防止意外丢失
💡 知识串联回忆: 在第6章”函数及其应用”中,我们学习了如何将程序的功能模块化。函数帮助我们更好地组织代码,而文件则帮助我们更好地管理数据。两者结合,就能构建出功能强大且数据可持久化的程序。

二、文件的类型:文本文件和二进制文件
按照存储方式的不同,文件可以分为两大类:文本文件和二进制文件。
1. 文本文件
文本文件是以字符编码(如 ASCII、UTF-8、GBK 等)形式存储数据的文件。文本文件中的每一个字节都对应一个字符,我们可以直接用文本编辑器(如记事本、VS Code 等)打开并阅读其中的内容。
常见的文本文件类型:
文件扩展名 | 说明 | 示例 |
.txt | 纯文本文件 | 笔记、日志 |
.py | Python 源代码文件 | 我们之前写的所有 .py 文件 |
.csv | 逗号分隔值文件 | 数据表格导出 |
.html | 网页文件 | 网页源代码 |
.json | JSON 数据文件 | 数据交换格式 |
.md | Markdown 文件 | 文档编写 |
【案例演示】 让我们用 Python 创建一个简单的文本文件来感受一下:
# ===== 创建一个文本文件 =====# 注意:这里我们先简单了解,后面7.1.2节会详细讲解open()函数# 使用open()函数创建并写入一个文本文件f = open("ck_students.txt", "w", encoding="utf-8")f.write("CK学校2025级数字经济专业学生名单\n")f.write("================================\n")f.write("学号\t姓名\t性别\n")f.write("2025001\t张三\t男\n")f.write("2025002\t李四\t女\n")f.write("2025003\t王五\t男\n")f.close()print("文本文件创建成功!")
文本文件创建成功!
上面的代码运行后,会在当前目录下生成一个名为 ck_students.txt 的文本文件。你可以用记事本或任何文本编辑器打开它,直接看到里面的中文内容。
💡 知识串联回忆: 上面的代码中用到了 f.write() 方法来写入字符串。回忆第2章”字符串类型及其处理”中,我们学习了字符串的各种操作方法,如 upper()、lower()、split() 等。而 write() 是文件对象的写入方法,它的参数就是一个字符串。这说明文件写入操作的基础,就是我们之前学过的字符串知识。
2. 二进制文件
二进制文件是以二进制编码(0和1)形式存储数据的文件。二进制文件中的数据不是直接对应可读字符,而是按照特定的文件格式来组织数据。我们无法用普通文本编辑器直接阅读二进制文件的内容(打开后通常显示为乱码)。
常见的二进制文件类型:
文件扩展名 | 说明 | 示例 |
.png / .jpg | 图片文件 | 照片、截图 |
.mp3 / .wav | 音频文件 | 音乐、录音 |
.mp4 / .avi | 视频文件 | 电影、短视频 |
.docx / .xlsx | Office 文档 | Word、Excel 文件 |
.pdf | PDF 文档 | 电子书、论文 |
.exe | 可执行文件 | Windows 程序 |
.pyc | Python 编译文件 | Python 字节码 |
【案例演示】 让我们用 Python 创建一个简单的二进制文件:
# ===== 创建一个二进制文件 =====# 注意:在文件打开模式中加 "b" 表示二进制模式# 以二进制写入模式打开文件f = open("ck_data.bin", "wb")# 写入二进制数据(bytes类型)# 回忆第2章:字符串前面加 b 表示bytes类型data = b"CK_School_Digital_Economy_2025"f.write(data)f.close()print("二进制文件创建成功!")print("写入的数据类型:", type(data))print("写入的数据内容:", data)
二进制文件创建成功!写入的数据类型:写入的数据内容: b'CK_School_Digital_Economy_2025'
💡 知识串联回忆: 上面的代码中出现了 b"..." 这种写法。回忆第2章”数据类型与变量”中,我们学习了字符串(str)类型。而 b"..." 是字节串(bytes)类型,它是字符串的二进制形式。在处理二进制文件时,我们需要使用 bytes 类型而不是 str 类型。
3. 文本文件与二进制文件的对比
让我们通过一个表格来清晰地对比两者的区别:
比较项 | 文本文件 | 二进制文件 |
存储方式 | 字符编码(ASCII、UTF-8等) | 二进制编码(0和1) |
可读性 | 可直接用文本编辑器阅读 | 需要专用软件打开 |
占用空间 | 通常较大 | 通常较小 |
使用场景 | 存储文本信息(文章、代码等) | 存储非文本信息(图片、音视频等) |
Python处理 | 默认以文本模式处理 | 需要指定二进制模式(“b”) |
编码方式 | 需要指定编码(如utf-8) | 不需要编码 |
【案例演示】 让我们通过代码来直观感受两种文件的区别:
# ===== 对比文本文件和二进制文件 =====# 1. 创建文本文件f_text = open("ck_demo_text.txt", "w", encoding="utf-8")f_text.write("重庆CK学校")f_text.close()# 2. 创建二进制文件f_bin = open("ck_demo_bin.bin", "wb")f_bin.write("重庆CK学校".encode("utf-8")) # 将字符串编码为bytesf_bin.close()# 3. 读取并对比文件大小import os # os模块:操作系统接口模块text_size = os.path.getsize("ck_demo_text.txt")bin_size = os.path.getsize("ck_demo_bin.bin")print(f"文本文件大小:{text_size} 字节")print(f"二进制文件大小:{bin_size} 字节")print(f"两者大小{'相同'if text_size == bin_size else'不同'}")
文本文件大小:18 字节二进制文件大小:18 字节两者大小相同
💡 知识说明: 在这个例子中,两种文件的大小相同,因为”重庆CK学校”这6个中文字符在 UTF-8 编码下每个占3个字节,共18个字节。文本文件和二进制文件在底层存储上本质都是二进制数据,区别在于我们如何解释这些数据——文本文件按照字符编码来解释,二进制文件按照特定格式来解释。
4. 如何判断文件类型
在日常生活中,我们可以通过文件的扩展名来判断文件类型。但在 Python 中,我们也可以通过代码来判断:
# ===== 判断文件类型 =====# 回忆第2章:字符串的endswith()方法filename1 = "ck_report.pdf"filename2 = "ck_notes.txt"filename3 = "ck_photo.jpg"filename4 = "ck_data.csv"# 使用字符串的endswith()方法判断文件扩展名# 回忆第3章:分支语句if-elif-elsedef get_file_type(filename): """根据文件扩展名判断文件类型""" # 回忆第5章:元组的定义和使用 text_extensions = (".txt", ".py", ".csv", ".html", ".json", ".md") binary_extensions = (".png", ".jpg", ".mp3", ".mp4", ".pdf", ".docx", ".exe") # 回忆第2章:字符串的lower()方法,统一转为小写 filename_lower = filename.lower() # 回忆第5章:使用for循环遍历元组 for ext in text_extensions: # 回忆第2章:字符串的endswith()方法 if filename_lower.endswith(ext): return "文本文件" for ext in binary_extensions: if filename_lower.endswith(ext): return "二进制文件" return "未知类型"# 测试# 回忆第4章:使用for循环遍历列表files = [filename1, filename2, filename3, filename4]for f in files: file_type = get_file_type(f) print(f"文件 '{f}' 的类型是:{file_type}")
文件 'ck_report.pdf' 的类型是:二进制文件文件 'ck_notes.txt' 的类型是:文本文件文件 'ck_photo.jpg' 的类型是:二进制文件文件 'ck_data.csv' 的类型是:文本文件
💡 知识串联总结: 上面的案例综合运用了我们之前学过的多个知识点: - 第2章:字符串的 lower() 和 endswith() 方法 - 第3章:if 分支语句进行条件判断 - 第4章:for 循环遍历列表和元组 - 第5章:元组的定义和使用 - 第6章:函数的定义和调用(get_file_type 函数)
可以看到,文件操作并不是孤立的知识,它需要我们综合运用前面学过的所有基础知识!

三、文件名
1. 文件名的组成
一个完整的文件名由主文件名和扩展名两部分组成,中间用英文句点(.)分隔:
主文件名 . 扩展名
例如: - ck_students.txt → 主文件名是 ck_students,扩展名是 .txt - report.pdf → 主文件名是 report,扩展名是 .pdf - photo.jpg → 主文件名是 photo,扩展名是 .jpg
扩展名的作用: 扩展名用来标识文件的类型,告诉操作系统应该用哪个程序来打开这个文件。例如,.py 文件会用 Python 解释器打开,.pdf 文件会用 PDF 阅读器打开。
2. 文件名的命名规则
在 Windows 操作系统中,文件名的命名需要遵循以下规则:
规则编号 | 规则说明 | 合法示例 | 非法示例 |
1 | 文件名长度不超过255个字符 | ck_student_records.txt | (超过255字符的文件名) |
2 | 不能包含以下字符:\ / : * ? " < > \| | ck_data_2025.txt | ck/data\2025.txt |
3 | 不能使用保留设备名 | my_con.txt | con.txt、aux.txt |
4 | 文件名不区分大小写 | CK.txt 和 ck.txt 是同一个文件 | — |
5 | 可以使用中文、空格和部分特殊字符 | CK 学校名单.txt | — |
💡 知识串联回忆: 对比第2章学过的标识符命名规则,文件名的命名规则与之有相似之处(都不能包含特殊字符),但也有不同(文件名可以使用中文和空格,而标识符不能)。
【案例演示】 让我们编写一个函数来检查文件名是否合法:
# ===== 文件名合法性检查 =====def check_filename(filename): """ 检查文件名是否合法 参数:filename - 要检查的文件名 返回:(是否合法, 原因说明) """ # 回忆第2章:len()函数获取字符串长度 if len(filename) == 0: return False, "文件名不能为空" if len(filename) > 255: return False, f"文件名长度{len(filename)}超过255个字符的限制" # 回忆第2章:字符串的成员运算 in # 回忆第5章:字符串也是序列,可以用for遍历 illegal_chars = '\\/:*?"<>|' # 回忆第4章:for循环遍历字符串 for char in filename: if char in illegal_chars: return False, f"文件名包含非法字符 '{char}'" # Windows保留设备名 # 回忆第5章:元组的定义 reserved_names = ("CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5") # 回忆第2章:字符串的upper()方法 # 回忆第2章:字符串的split()方法 name_part = filename.split(".")[0].upper() # 回忆第5章:使用in判断元素是否在元组中 if name_part in reserved_names: return False, f"文件名使用了保留设备名 '{name_part}'" return True, "文件名合法"# 测试# 回忆第5章:列表的定义和使用test_names = [ "ck_students.txt", # 合法 "CK 学校名单.txt", # 合法(含中文和空格) "data/file.txt", # 非法(含/) "report*.pdf", # 非法(含*) "con.txt", # 非法(保留设备名) "", # 非法(空文件名) "a" * 300 + ".txt", # 非法(超长)]# 回忆第4章:for循环遍历列表for name in test_names: is_valid, reason = check_filename(name) # 回忆第3章:条件表达式(三元运算符) status = "✓ 合法" if is_valid else "✗ 非法" # 如果文件名太长,只显示前30个字符 display_name = name[:30] + "..." if len(name) > 30 else name print(f"{status} | '{display_name}' — {reason}")
✓ 合法 | 'ck_students.txt' — 文件名合法✓ 合法 | 'CK 学校名单.txt' — 文件名合法✗ 非法 | 'data/file.txt' — 文件名包含非法字符 '/'✗ 非法 | 'report*.pdf' — 文件名包含非法字符 '*'✗ 非法 | 'con.txt' — 文件名使用了保留设备名 'CON'✗ 非法 | '' — 文件名不能为空✗ 非法 | 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' — 文件名长度300超过255个字符的限制
💡 知识串联总结: 这个案例综合运用了: - 第2章:len() 函数、字符串的 split()、upper() 方法、in 成员运算 - 第3章:条件表达式(三元运算符 x if condition else y) - 第4章:for 循环遍历字符串和列表 - 第5章:元组的定义、in 运算符判断元素是否在元组中 - 第6章:函数的定义与调用、返回多个值(元组解包)

四、文件路径
1. 什么是文件路径
文件路径是指文件在计算机文件系统中的位置信息,它告诉操作系统去哪里找到这个文件。就像我们寄快递需要填写收货地址一样,程序要访问文件也需要知道文件的”地址”——也就是文件路径。
2. 绝对路径
绝对路径是从计算机的根目录开始,一直到目标文件的完整路径。绝对路径的特点是唯一确定,无论你当前在哪个目录下,使用绝对路径都能找到同一个文件。
Windows 系统中的绝对路径格式:
盘符:\文件夹1\文件夹2\...\文件名.扩展名
【示例】
C:\Users\student\Desktop\ck_homework\python_lesson7.txtD:\CK\数字经济专业\2025春\学生名单.csv
Linux/Mac 系统中的绝对路径格式:
/文件夹1/文件夹2/.../文件名.扩展名
【示例】
/home/student/ck_homework/python_lesson7.txt/Users/student/CK/数字经济专业/2025春/学生名单.csv
💡 注意: Windows 系统使用反斜杠 \ 作为路径分隔符,而 Linux/Mac 系统使用正斜杠 / 作为路径分隔符。在 Python 中,我们可以使用正斜杠 / 来兼容不同操作系统(Python 会自动处理),也可以使用双反斜杠 \\ 来表示一个反斜杠。
3. 相对路径
相对路径是相对于当前工作目录的路径。相对路径不以盘符或根目录开头,而是从当前目录出发来定位文件。
相对路径中的特殊符号:
符号 | 含义 | 说明 |
. | 当前目录 | 表示文件所在的当前文件夹 |
.. | 上一级目录(父目录) | 表示当前目录的上一级文件夹 |
【示例】 假设当前工作目录是 D:\CK\数字经济专业\Python课程:
相对路径 | 实际指向的绝对路径 |
lesson7.txt | D:\CK\数字经济专业\Python课程\lesson7.txt |
.\lesson7.txt | D:\CK\数字经济专业\Python课程\lesson7.txt |
..\学生名单.csv | D:\CK\数字经济专业\学生名单.csv |
..\..\校历.txt | D:\CK\校历.txt |
.\homework\作业1.py | D:\CK\数字经济专业\Python课程\homework\作业1.py |
4. 在 Python 中使用文件路径
Python 提供了 os 模块来处理文件路径相关的操作。os 是 “operating system”(操作系统)的缩写,它是 Python 的标准库模块之一。
💡 知识串联回忆: 在第6章”函数及其应用”中,我们学习了 time 库和 turtle 库两个标准库模块。os 模块同样是一个标准库模块,不需要额外安装就可以直接使用。回忆第1章”Python程序的模块及引用”中,我们学过使用 import 语句来导入模块。
【案例演示】 让我们通过代码来学习路径操作:
# ===== 文件路径操作 =====import os # 导入os模块# 1. 获取当前工作目录current_dir = os.getcwd()print(f"当前工作目录:{current_dir}")# 2. 路径拼接 —— 使用 os.path.join()# 回忆第2章:字符串的拼接# 但路径拼接推荐使用 os.path.join(),因为它能自动处理不同操作系统的分隔符# 不推荐的方式(手动拼接字符串)path_manual = current_dir + "\\ck_data" + "\\students.txt"print(f"\n手动拼接的路径:{path_manual}")# 推荐的方式(使用os.path.join)path_join = os.path.join(current_dir, "ck_data", "students.txt")print(f"os.path.join拼接的路径:{path_join}")# 3. 获取文件名和目录名full_path = r"D:\CK\数字经济专业\Python课程\lesson7.py"# 回忆第2章:字符串前加 r 表示原始字符串(raw string),不转义反斜杠dirname = os.path.dirname(full_path)basename = os.path.basename(full_path)print(f"\n完整路径:{full_path}")print(f"目录名:{dirname}")print(f"文件名:{basename}")# 4. 分离文件名和扩展名name, ext = os.path.splitext(basename)print(f"\n主文件名:{name}")print(f"扩展名:{ext}")# 5. 判断路径是否存在print(f"\n当前目录是否存在:{os.path.exists(current_dir)}")print(f"不存在的路径是否存在:{os.path.exists('D:\\不存在的路径\\文件.txt')}")
当前工作目录:/home/student手动拼接的路径:/home/student\ck_data\students.txtos.path.join拼接的路径:/home/student/ck_data/students.txt完整路径:D:\CK\数字经济专业\Python课程\lesson7.py目录名:D:\CK\数字经济专业\Python课程文件名:lesson7.py主文件名:lesson7扩展名:.py当前目录是否存在:True不存在的路径是否存在:False
💡 重要提示: 在 Python 字符串中,反斜杠 \ 是转义字符的前缀。例如 \n 表示换行,\t 表示制表符。因此,如果路径中包含反斜杠,我们需要: 1. 使用双反斜杠\\:"D:\\CK\\data.txt" 2. 使用原始字符串r"...":r"D:\CK\data.txt"(推荐) 3. 使用正斜杠/:"D:/CK/data.txt"(推荐,跨平台兼容)
【案例演示】 让我们设计一个更贴近实际的案例——模拟 CK 学校的文件目录结构:
# ===== CK学校文件目录结构模拟 =====import os# 模拟CK学校的文件目录结构# 使用字典来表示目录结构(回忆第5章:字典的定义和使用)ck_structure = { "CK学校": { "经济管理学院": { "数字经济专业": { "2025春学期": { "课程材料": ["讲义.docx", "PPT.pptx", "案例.txt"], "学生作业": ["作业1_张三.py", "作业2_李四.py"], "考试成绩": ["期中成绩.csv", "期末成绩.csv"] } } }, "校务文件": ["校历.txt", "通知.txt", "课表.csv"] }}# 递归函数打印目录结构# 回忆第6章:递归函数def print_directory_structure(structure, indent=0): """ 递归打印目录结构 参数: structure - 目录结构字典或列表 indent - 缩进级别 """ # 回忆第4章:for循环 # 回忆第5章:字典的items()方法 if isinstance(structure, dict): for key, value in structure.items(): # 回忆第2章:字符串乘法实现重复 print(" " * indent + "📁 " + key) print_directory_structure(value, indent + 1) elif isinstance(structure, list): for item in structure: print(" " * indent + "📄 " + item)# 打印目录结构print("=" * 50)print("CK学校文件目录结构")print("=" * 50)print_directory_structure(ck_structure)
==================================================CK学校文件目录结构==================================================📁 CK学校📁 经济管理学院📁 数字经济专业📁 2025春学期📁 课程材料📄 讲义.docx📄 PPT.pptx📄 案例.txt📁 学生作业📄 作业1_张三.py📄 作业2_李四.py📁 考试成绩📄 期中成绩.csv📄 期末成绩.csv📁 校务文件📄 校历.txt📄 通知.txt📄 课表.csv
💡 知识串联总结: 这个案例综合运用了: - 第2章:字符串乘法 "" * indent、isinstance() 函数判断数据类型 - 第4章:for 循环遍历字典和列表 - 第5章:字典的嵌套定义、items() 方法、isinstance() 类型判断 - 第6章:递归函数的定义与调用
5. 绝对路径与相对路径的对比
比较项 | 绝对路径 | 相对路径 |
起点 | 从根目录开始 | 从当前工作目录开始 |
完整性 | 包含完整路径信息 | 只包含相对位置信息 |
移植性 | 差(换一台电脑路径可能不同) | 好(只要目录结构相同就能用) |
使用场景 | 需要精确定位文件时 | 项目内部文件引用时 |
示例 | D:\CK\data\students.txt | .\data\students.txt |
💡 实践建议: 在编写 Python 程序时,推荐优先使用相对路径,因为相对路径具有更好的移植性。当你把整个项目文件夹复制到另一台电脑时,相对路径仍然有效,而绝对路径可能因为盘符或用户名不同而失效。

五、文件的两种基本操作
1. 概述
对文件的操作,归根结底就是两种最基本的操作:读(Read) 和 写(Write)。
·读操作(输入):将文件中的数据读取到程序的内存中,供程序处理使用
·写操作(输出):将程序内存中的数据写入到文件中,实现数据持久化
读操作:文件(外存) ——→ 程序(内存)写操作:程序(内存) ——→ 文件(外存)
💡 知识串联回忆: 这个概念和第2章学过的 input() 和 print() 非常类似: - input() 是从键盘读取数据到程序(标准输入) - print() 是将程序数据输出到屏幕(标准输出) - 文件读操作是从文件读取数据到程序(文件输入) - 文件写操作是将程序数据输出到文件(文件输出)
可以把文件看作是键盘和屏幕之外的”第三种”输入输出设备!
2. 读操作和写操作的完整流程
无论是读操作还是写操作,都需要遵循以下三步流程:
第一步:打开文件(open)—— 建立程序与文件的连接第二步:读/写文件(read/write)—— 进行数据交换第三步:关闭文件(close)—— 断开连接,释放资源
这个流程就像打电话一样: 1. 打开文件 = 拨打电话(建立连接) 2. 读/写文件 = 通话交流(交换信息) 3. 关闭文件 = 挂断电话(断开连接)
【案例演示】 让我们用伪代码来展示读操作和写操作的完整流程:
# ===== 文件操作的完整流程(伪代码演示) =====# ---------- 写操作流程 ----------# 第一步:打开文件(以写入模式)f = open("ck_message.txt", "w", encoding="utf-8")# 第二步:写入数据f.write("欢迎来到CK学校数字经济专业!\n")f.write("Python编程让数据创造价值!\n")# 第三步:关闭文件f.close()print("写操作完成!")# ---------- 读操作流程 ----------# 第一步:打开文件(以读取模式)f = open("ck_message.txt", "r", encoding="utf-8")# 第二步:读取数据content = f.read()print("文件内容:")print(content)# 第三步:关闭文件f.close()print("读操作完成!")
写操作完成!文件内容:欢迎来到CK学校数字经济专业!Python编程让数据创造价值!读操作完成!
💡 重要提醒: 上面的代码中,open() 函数的第一个参数是文件名,第二个参数是打开模式("w" 表示写入,"r" 表示读取),第三个参数 encoding="utf-8" 指定了文件的编码方式。关于 open() 函数的详细用法,我们将在下一节 7.1.2 文件的打开与关闭 中深入学习。
3. 文件操作与之前学过的知识的对比
让我们通过一个表格,将文件操作与之前学过的输入输出方式进行对比:
比较项 | input() / print() | 文件读/写操作 |
数据来源/去向 | 键盘 / 屏幕 | 文件 |
数据持久性 | 临时(程序结束即消失) | 永久(保存在硬盘上) |
数据量 | 少量(逐行交互) | 大量(批量处理) |
使用场景 | 人机交互 | 数据存储与交换 |
操作步骤 | 直接调用函数 | 需要先打开文件,操作后关闭文件 |
所属章节 | 第2章 | 第7章(本章) |
💡 学习建议: 理解了文件读/写操作与 input()/print() 的类比关系后,你会发现文件操作并不难——它只是把数据的”来源”和”去向”从键盘和屏幕换成了文件而已。核心的编程逻辑(变量、分支、循环、函数等)都是一样的!

🤖 AI辅助学习小节(7.1.1)
同学们,学完7.1.1节后,如何利用AI工具来巩固和加深对本节知识的理解呢?下面是为你精心设计的AI互动练习方案!
练习一:用AI帮你生成一个”重庆美食推荐”文本文件
练习目标: 综合运用文件写入操作和字符串知识,创建一个包含重庆美食信息的文本文件。
AI提示词(直接复制发送给AI):
我是一个Python初学者,正在学习文件操作。请帮我编写一个Python程序,完成以下任务:1. 创建一个名为"chongqing_food.txt"的文本文件2. 写入以下重庆美食推荐信息(使用UTF-8编码):- 标题:"重庆必吃美食推荐"- 至少包含5种重庆美食的名称、推荐指数(1-5星)、简短描述- 使用制表符或空格对齐格式3. 写入完成后,再读取文件内容并打印到屏幕上4. 请在代码中添加详细的中文注释,解释每一步的作用要求:代码要简洁易懂,适合初学者理解。
学习要点: 通过这个练习,你将巩固 open() 函数的 "w" 和 "r" 模式、write() 方法、read() 方法以及 close() 方法的使用。

练习二:用AI帮你设计一个”文件路径探索器”
练习目标: 综合运用 os 模块和之前学过的数据类型知识,探索文件路径。
AI提示词(直接复制发送给AI):
请帮我编写一个Python程序,实现一个"文件路径探索器"功能:1. 使用os模块获取当前工作目录2. 列出当前目录下的所有文件和文件夹3. 对每个文件,判断它是文本文件还是二进制文件(通过扩展名判断)4. 对每个文件,显示以下信息:- 文件名- 文件大小(字节)- 文件类型(文本/二进制)5. 最后统计文本文件和二进制文件的数量请使用列表和字典来组织数据,代码要有详细的中文注释。
学习要点: 通过这个练习,你将巩固 os.getcwd()、os.listdir()、os.path 相关方法的使用,同时复习第5章的列表和字典知识。

练习三:用AI帮你创建一个”ASCII艺术重庆地标”
练习目标: 将字符串知识和文件写入结合,创建一个有趣的ASCII艺术文件。
AI提示词(直接复制发送给AI):
请帮我用Python创建一个ASCII艺术文件,内容是重庆的标志性建筑(如解放碑、洪崖洞、长江索道等)的简笔画。要求:1. 使用Python字符串来绘制ASCII艺术图案2. 将图案写入到一个名为"chongqing_landmark.txt"的文本文件中3. 图案要尽量美观,能看出建筑的特征4. 在图案下方添加一段关于该地标的文字介绍5. 最后读取文件内容并打印显示请选择2-3个重庆地标来绘制,代码要有详细注释。
学习要点: 通过这个有趣的练习,你将发现文件操作可以用来保存各种创意内容,同时复习多行字符串(三引号 """...""")的使用方法。

练习四:用AI帮你制作一个”学习进度记录器”
练习目标: 综合运用文件追加写入和用户交互知识。
AI提示词(直接复制发送给AI):
请帮我编写一个Python"学习进度记录器"程序:功能要求:1. 程序运行时,提示用户输入今天的学习内容(如学习了哪个章节、掌握了哪些知识点)2. 将用户输入的内容追加写入到"study_log.txt"文件中(注意:是追加,不是覆盖)3. 每条记录前面加上日期时间信息4. 写入完成后,读取并显示文件中的所有历史记录5. 使用循环让用户可以连续输入多条记录,输入"退出"时结束程序请使用input()获取用户输入,用文件追加模式写入,代码要有详细中文注释。
学习要点: 通过这个练习,你将初步了解文件的追加模式("a" 模式),同时复习第2章的 input() 函数和第4章的循环结构。

📝 自学检查清单
完成以上AI辅助练习后,请对照以下清单检查自己的掌握情况:
☐我能解释什么是文件,以及文件与变量的区别
☐我能区分文本文件和二进制文件,并各举出3个例子
☐我能说出文件名的命名规则,并判断一个文件名是否合法
☐我能区分绝对路径和相对路径,并各写出一个例子
☐我能使用 os.path.join() 来拼接文件路径
☐我能说出文件操作的”三步流程”
☐我能解释文件读/写操作与 input()/print() 的相似之处

7.1.2 文件的打开与关闭
📖 本节导读
在上一节(7.1.1)中,我们学习了文件的基本概念,了解了文件的类型、命名规则、路径以及文件操作的”三步流程”:打开文件 → 读/写文件 → 关闭文件。
本节我们将深入学习这”三步流程”中的第一步和第三步——如何使用 Python 的 open() 函数打开文件,以及如何使用 close() 方法关闭文件。至于中间的”读/写文件”部分,我们将在7.2节中详细学习。
💡 知识串联回忆: 在第6章”函数及其应用”中,我们学习了函数的定义和调用。open() 是 Python 的一个内置函数(回忆第2章学过的 print()、input()、len() 等内置函数),而 close() 是文件对象的方法(回忆第2章学过的字符串方法 upper()、lower() 等)。理解函数和方法的区别,有助于我们更好地使用它们。

一、打开文件——open() 函数
1. open() 函数的基本语法
open() 是 Python 中用于打开文件的内置函数,它的基本语法如下:
open(file, mode='r', encoding=None)
参数说明:
参数 | 说明 | 是否必填 | 默认值 |
file | 文件名或文件路径 | 是 | 无 |
mode | 文件打开模式 | 否 | 'r'(只读模式) |
encoding | 文件编码方式 | 否 | 系统默认编码 |
返回值:open() 函数返回一个文件对象(file object),我们可以通过这个文件对象来对文件进行读写操作。
💡 知识串联回忆: 回忆第2章”数据类型与变量”,我们学习了 int、float、str、bool 等数据类型。文件对象(file object)是 Python 中的另一种数据类型。就像字符串有 upper()、split() 等方法一样,文件对象也有自己的方法,如 read()、write()、close() 等。
2. 文件打开模式详解
open() 函数的 mode 参数决定了我们以什么方式打开文件。Python 提供了以下几种常用的打开模式:
(1)只读模式 —— "r"
"r" 模式是默认模式,用于读取文件内容。如果文件不存在,会报错(FileNotFoundError)。
# ===== 只读模式 "r" =====# 打开一个已存在的文件进行读取f = open("ck_message.txt", "r", encoding="utf-8")# 读取文件全部内容content = f.read()print(content)# 关闭文件f.close()
欢迎来到CK学校数字经济专业!Python编程让数据创造价值!
⚠️ 注意: 使用 "r" 模式打开文件时,文件必须已经存在。如果文件不存在,Python 会抛出 FileNotFoundError 异常。回忆第3章”复杂分支程序设计”中,我们学习了程序异常处理(try-except),可以用它来处理文件不存在的错误。
【案例演示】 让我们结合第3章学过的异常处理来安全地打开文件:
# ===== 使用异常处理安全打开文件 =====# 回忆第3章:try-except异常处理filename = "not_exist_file.txt"try: f = open(filename, "r", encoding="utf-8") content = f.read() print(content) f.close()except FileNotFoundError: print(f"错误:文件 '{filename}' 不存在!") print("请检查文件名和路径是否正确。")
错误:文件 'not_exist_file.txt' 不存在!请检查文件名和路径是否正确。
💡 知识串联总结: 这个案例展示了第3章异常处理在文件操作中的实际应用。在实际编程中,文件操作经常会遇到各种异常(文件不存在、权限不足等),使用 try-except 可以让程序更加健壮。
(2)只写模式 —— "w"
"w" 模式用于写入文件内容。如果文件不存在,会自动创建新文件;如果文件已存在,会清空原有内容后重新写入(覆盖)。
# ===== 只写模式 "w" =====# 1. 写入一个新文件(文件不存在时自动创建)f = open("ck_new_file.txt", "w", encoding="utf-8")f.write("这是第一次写入的内容。\n")f.close()print("新文件创建并写入成功!")# 2. 再次以"w"模式打开同一个文件(会清空原有内容)f = open("ck_new_file.txt", "w", encoding="utf-8")f.write("这是第二次写入的内容,之前的内容被覆盖了。\n")f.close()print("文件内容已被覆盖!")# 3. 读取文件验证内容f = open("ck_new_file.txt", "r", encoding="utf-8")print("文件当前内容:")print(f.read())f.close()
新文件创建并写入成功!文件内容已被覆盖!文件当前内容:这是第二次写入的内容,之前的内容被覆盖了。
⚠️ 重要警告:"w" 模式会清空文件中的原有内容!这是一个非常容易犯错的地方。如果你不小心用 "w" 模式打开了一个重要文件,里面的内容会被全部删除。因此,在使用 "w" 模式之前,一定要确认是否需要保留原有内容。
【案例演示】 让我们设计一个 CK 学校的成绩录入案例:
# ===== CK学校成绩录入案例 =====# 回忆第5章:使用列表存储多条数据# 回忆第2章:input()函数获取用户输入def write_scores(): """将学生成绩写入文件""" # 使用"w"模式创建新文件 f = open("ck_scores.txt", "w", encoding="utf-8") # 写入表头 f.write("CK学校 数字经济专业 Python课程成绩单\n") f.write("=" * 40 + "\n") f.write(f"{'学号':<10}{'姓名':<8}{'成绩':<8}{'等级':<6}\n") f.write("-" * 40 + "\n") # 学生数据(使用列表存储) # 回忆第5章:列表中存储字典 students = [ {"id": "2025001", "name": "张三", "score": 92}, {"id": "2025002", "name": "李四", "score": 85}, {"id": "2025003", "name": "王五", "score": 78}, {"id": "2025004", "name": "赵六", "score": 95}, {"id": "2025005", "name": "钱七", "score": 63}, ] # 回忆第4章:for循环遍历列表 # 回忆第3章:if-elif-else多路分支 for stu in students: # 根据成绩判断等级 # 回忆第3章:关系运算和分支语句 if stu["score"] >= 90: grade = "优秀" elif stu["score"] >= 80: grade = "良好" elif stu["score"] >= 70: grade = "中等" elif stu["score"] >= 60: grade = "及格" else: grade = "不及格" # 写入每个学生的信息 # 回忆第2章:f-string格式化字符串 f.write(f"{stu['id']:<10}{stu['name']:<8}{stu['score']:<8}{grade:<6}\n") f.close() print("成绩单已写入文件 ck_scores.txt")# 调用函数write_scores()# 读取并显示文件内容f = open("ck_scores.txt", "r", encoding="utf-8")print("\n" + f.read())f.close()
成绩单已写入文件 ck_scores.txtCK学校 数字经济专业 Python课程成绩单========================================学号姓名成绩等级----------------------------------------2025001张三92优秀2025002李四85良好2025003王五78中等2025004赵六95优秀2025005钱七63及格
💡 知识串联总结: 这个案例综合运用了: - 第2章:f-string 格式化字符串、字符串对齐(<10 表示左对齐占10个字符宽度) - 第3章:if-elif-else 多路分支语句判断成绩等级 - 第4章:for 循环遍历学生列表 - 第5章:列表存储字典数据 - 第6章:函数的定义和调用
(3)追加模式 —— "a"
"a" 模式用于追加内容到文件末尾。如果文件不存在,会自动创建新文件;如果文件已存在,会在文件末尾添加新内容,不会覆盖原有内容。
# ===== 追加模式 "a" =====# 1. 先创建一个文件并写入初始内容f = open("ck_log.txt", "w", encoding="utf-8")f.write("=== CK学校活动日志 ===\n")f.write("2025-03-01 新学期开学典礼\n")f.close()print("初始文件创建完成")# 2. 使用"a"模式追加新内容f = open("ck_log.txt", "a", encoding="utf-8")f.write("2025-03-15 Python编程竞赛\n")f.write("2025-04-01 数字经济讲座\n")f.close()print("第一次追加完成")# 3. 再次追加更多内容f = open("ck_log.txt", "a", encoding="utf-8")f.write("2025-04-20 期中考试\n")f.write("2025-05-05 文件操作课程\n")f.close()print("第二次追加完成")# 4. 读取完整文件内容f = open("ck_log.txt", "r", encoding="utf-8")print("\n文件完整内容:")print(f.read())f.close()
初始文件创建完成第一次追加完成第二次追加完成文件完整内容:=== CK学校活动日志 ===2025-03-01 新学期开学典礼2025-03-15 Python编程竞赛2025-04-01 数字经济讲座2025-04-20 期中考试2025-05-05 文件操作课程
💡 对比理解:"w" 模式和 "a" 模式的区别非常重要! - "w" 模式:覆盖写入——就像用橡皮擦擦掉黑板上的所有内容,重新书写 - "a" 模式:追加写入——就像在笔记本的最后一行后面继续写新内容
在实际开发中,日志记录通常使用 "a" 模式,因为我们需要保留之前的历史记录。
【案例演示】 让我们设计一个”学习日志”程序,综合运用追加模式和用户交互:
# ===== CK学校学习日志程序 =====import time # 回忆第6章:time标准库模块def add_log_entry(): """添加一条学习日志""" # 获取当前时间 # 回忆第6章:time.strftime()格式化时间 current_time = time.strftime("%Y-%m-%d %H:%M:%S") # 获取用户输入 # 回忆第2章:input()函数 print(f"\n当前时间:{current_time}") content = input("请输入今天的学习内容:") # 使用"a"模式追加写入 f = open("ck_study_log.txt", "a", encoding="utf-8") f.write(f"[{current_time}] {content}\n") f.close() print("日志记录成功!")def show_all_logs(): """显示所有学习日志""" try: f = open("ck_study_log.txt", "r", encoding="utf-8") content = f.read() f.close() if content: # 回忆第3章:空字符串为False print("\n" + "=" * 50) print("CK学校学习日志") print("=" * 50) print(content) else: print("\n暂无学习日志记录。") except FileNotFoundError: print("\n暂无学习日志记录。")# 主程序# 回忆第3章:分支语句# 回忆第4章:while循环print("=" * 50)print(" CK学校学习日志系统")print("=" * 50)while True: print("\n请选择操作:") print("1. 记录学习内容") print("2. 查看所有日志") print("3. 退出程序") choice = input("请输入选项(1/2/3):") # 回忆第3章:if-elif-else分支 if choice == "1": add_log_entry() elif choice == "2": show_all_logs() elif choice == "3": print("感谢使用,再见!") break # 回忆第4章:break语句退出循环 else: print("无效选项,请重新输入。")
==================================================CK学校学习日志系统==================================================请选择操作:1. 记录学习内容2. 查看所有日志3. 退出程序请输入选项(1/2/3):1当前时间:2025-05-05 14:30:00请输入今天的学习内容:学习了Python文件操作的基本概念日志记录成功!请选择操作:1. 记录学习内容2. 查看所有日志3. 退出程序请输入选项(1/2/3):2==================================================CK学校学习日志==================================================[2025-05-05 14:30:00] 学习了Python文件操作的基本概念请选择操作:1. 记录学习内容2. 查看所有日志3. 退出程序请输入选项(1/2/3):3感谢使用,再见!
💡 知识串联总结: 这个案例是一个小型综合项目,综合运用了: - 第2章:input() 函数、字符串格式化 - 第3章:if-elif-else 分支语句、try-except 异常处理 - 第4章:while True 无限循环、break 退出循环 - 第6章:time 标准库模块的使用、函数的定义和调用 - 第7章:文件的打开("a" 和 "r" 模式)、写入、读取、关闭
(4)读写模式 —— "+"
"+" 模式本身不能单独使用,它需要与其他模式组合使用,表示在原有模式的基础上增加读或写的能力。
常用的组合模式:
模式 | 名称 | 说明 |
"r+" | 读写模式 | 打开文件用于读和写(文件必须存在) |
"w+" | 写读模式 | 打开文件用于写和读(文件不存在则创建,存在则清空) |
"a+" | 追加读写模式 | 打开文件用于追加和读(文件不存在则创建) |
【案例演示】 让我们通过代码来理解 "r+" 模式:
# ===== "r+" 读写模式演示 =====# 先创建一个文件f = open("ck_demo.txt", "w", encoding="utf-8")f.write("ABCDEFG")f.close()# 使用"r+"模式打开(可读可写)f = open("ck_demo.txt", "r+", encoding="utf-8")# 读取当前内容content = f.read()print(f"读取的内容:{content}")# 写入新内容(注意:写入位置在文件末尾,因为read()已经把指针移到了末尾)f.write("XYZ")print("已写入 XYZ")# 将文件指针移回开头(使用seek方法)f.seek(0)content = f.read()print(f"写入后的内容:{content}")f.close()
读取的内容:ABCDEFG已写入 XYZ写入后的内容:ABCDEFGXYZ
💡 补充说明: 上面的代码中出现了一个新概念——文件指针。文件指针就像读书时的”书签”,它标记了当前读/写的位置。read() 方法会从文件指针的位置开始读取,读取后指针会移动到文件末尾。seek(0) 方法可以将指针移回文件开头。关于文件指针的更多知识,我们将在7.2节中深入学习。
(5)二进制模式 —— "b"
"b" 模式用于以二进制方式打开文件,它需要与其他模式组合使用。
模式 | 说明 |
"rb" | 以二进制只读模式打开 |
"wb" | 以二进制只写模式打开 |
"ab" | 以二进制追加模式打开 |
"rb+" | 以二进制读写模式打开 |
💡 注意: 使用二进制模式时,不需要指定 encoding 参数(因为二进制文件不涉及字符编码),并且读写的数据类型是 bytes 而不是 str。
# ===== 二进制模式演示 =====# 以二进制写入模式创建文件f = open("ck_binary.dat", "wb")# 写入bytes类型的数据f.write(b"CK_School_2025")f.close()# 以二进制读取模式打开文件f = open("ck_binary.dat", "rb")data = f.read()f.close()print(f"读取的数据:{data}")print(f"数据类型:{type(data)}")
读取的数据:b'CK_School_2025'数据类型:
3. 文件打开模式汇总表
为了方便大家记忆和查阅,下面将所有文件打开模式汇总如下:
模式 | 名称 | 文件不存在时 | 文件已存在时 | 能否读 | 能否写 |
"r" | 只读 | 报错 | 从头读取 | 能 | 不能 |
"w" | 只写 | 创建新文件 | 清空后写入 | 不能 | 能 |
"a" | 追加 | 创建新文件 | 末尾追加 | 不能 | 能 |
"r+" | 读写 | 报错 | 从头读写 | 能 | 能 |
"w+" | 写读 | 创建新文件 | 清空后读写 | 能 | 能 |
"a+" | 追加读写 | 创建新文件 | 末尾追加并可读 | 能 | 能 |
"rb" | 二进制只读 | 报错 | 从头读取 | 能 | 不能 |
"wb" | 二进制只写 | 创建新文件 | 清空后写入 | 不能 | 能 |
"ab" | 二进制追加 | 创建新文件 | 末尾追加 | 不能 | 能 |
💡 记忆技巧: - r = read(读),w = write(写),a = append(追加) - + = 加上另一种能力(读+写) - b = binary(二进制) - "w" 是最”危险”的模式,因为它会清空原有内容!
【案例演示】 让我们编写一个函数来演示不同模式的行为差异:
# ===== 文件模式对比演示 =====def demo_mode(mode_name, mode, filename="ck_mode_test.txt"): """演示不同文件打开模式的行为""" print(f"\n{'='*50}") print(f"演示模式:{mode_name}('{mode}')") print(f"{'='*50}") try: f = open(filename, mode, encoding="utf-8") print(f"文件打开成功!") # 尝试读取 try: pos = f.tell() # 获取当前文件指针位置 content = f.read() if content: print(f"读取到的内容:{repr(content)}") else: print(f"读取到的内容:(空)") except: print(f"此模式不支持读取操作") f.close() except FileNotFoundError: print(f"文件不存在,无法以'{mode}'模式打开!") except Exception as e: print(f"发生错误:{e}")# 依次演示各种模式# 回忆第5章:使用列表存储多种模式modes = [ ("只读模式", "r"), ("只写模式", "w"), ("追加模式", "a"),]for name, mode in modes: demo_mode(name, mode)
==================================================演示模式:只读模式('r')==================================================文件打开成功!读取到的内容:(空)==================================================演示模式:只写模式('w')==================================================文件打开成功!此模式不支持读取操作==================================================演示模式:追加模式('a')==================================================文件打开成功!此模式不支持读取操作
💡 知识串联总结: 这个案例综合运用了: - 第3章:try-except 异常处理 - 第4章:for 循环遍历列表 - 第5章:列表存储元组数据 - 第6章:函数的定义和调用

二、关闭文件——close() 方法
1. 为什么要关闭文件
当我们使用 open() 函数打开一个文件后,操作系统会为这个文件分配一定的系统资源(称为”文件句柄”或”文件描述符”)。如果打开文件后不关闭,这些资源就会一直被占用,导致以下问题:
1.资源浪费:操作系统能同时打开的文件数量是有限的(通常几百到几千个),如果不关闭文件,可能导致后续无法打开新文件。
2.数据丢失:写入文件的数据可能暂时存储在缓冲区(内存中的一块区域)中,还没有真正写入硬盘。调用 close() 方法会强制将缓冲区中的数据写入硬盘,确保数据不丢失。
3.文件被锁定:在 Windows 系统中,一个文件被打开后可能会被”锁定”,其他程序无法访问该文件,直到它被关闭。
💡 类比理解: 打开文件就像从图书馆借了一本书,关闭文件就像把书还回图书馆。如果你借了书不还,别人就借不到这本书了。同样,如果你打开了文件不关闭,其他程序可能就无法访问这个文件了。
2. close() 方法的使用
close() 是文件对象的方法,用于关闭文件并释放系统资源。它的语法非常简单:
文件对象.close()
【正确示例】
# ===== 正确的文件操作流程 =====# 第一步:打开文件f = open("ck_example.txt", "w", encoding="utf-8")# 第二步:写入数据f.write("CK学校数字经济专业\n")f.write("Python基础及应用课程\n")# 第三步:关闭文件(非常重要!)f.close()print("文件操作完成,文件已关闭。")
文件操作完成,文件已关闭。
3. 忘记关闭文件的后果
让我们通过一个案例来演示忘记关闭文件可能带来的问题:
# ===== 忘记关闭文件的后果演示 =====import os# 正确关闭文件的情况f1 = open("ck_test1.txt", "w", encoding="utf-8")f1.write("这是正确关闭的文件")f1.close() # 正确关闭# 检查文件内容f1 = open("ck_test1.txt", "r", encoding="utf-8")print(f"正确关闭的文件内容:{f1.read()}")f1.close()print("\n--- 分割线 ---\n")# 模拟忘记关闭文件的情况(仅作演示,实际编程中不要这样做)# 注意:在Jupyter Notebook中,由于缓冲机制,数据可能仍然会被写入# 但在正式的程序中,忘记关闭文件可能导致数据丢失f2 = open("ck_test2.txt", "w", encoding="utf-8")f2.write("这是没有关闭的文件")# 故意不调用 f2.close()# 在某些情况下,文件可能为空或内容不完整# 因为数据可能还在缓冲区中,没有被刷新到硬盘print("注意:在实际编程中,忘记关闭文件可能导致数据丢失!")print("因此,每次打开文件后,一定要记得关闭!")
正确关闭的文件内容:这是正确关闭的文件--- 分割线 ---注意:在实际编程中,忘记关闭文件可能导致数据丢失!因此,每次打开文件后,一定要记得关闭!
4. 确保文件被关闭的最佳实践
在实际编程中,我们可能会遇到各种情况导致 close() 没有被执行(比如程序在写入数据时发生了异常)。为了确保文件一定会被关闭,Python 提供了以下几种方法:
方法一:使用 try-finally(回忆第3章异常处理)
# ===== 使用 try-finally 确保关闭文件 =====# 回忆第3章:try-finally语句# finally块中的代码无论是否发生异常都会执行f = None # 先将f设为Nonetry: f = open("ck_important.txt", "w", encoding="utf-8") f.write("这是一条重要的数据\n") f.write("CK学校数字经济专业\n") # 假设这里可能发生异常 result = 10 / 0 # 这会引发ZeroDivisionErrorexcept ZeroDivisionError: print("发生了除零错误!")finally: # 无论是否发生异常,finally块都会执行 if f is not None: # 回忆第2章:is运算符(第3章也学过) f.close() print("文件已关闭(通过finally确保)")
发生了除零错误!文件已关闭(通过finally确保)
💡 知识串联回忆: 在第3章”复杂分支程序设计”中,我们学习了 try-except 异常处理。try-finally 是异常处理的另一种形式,finally 块中的代码无论是否发生异常都会执行,非常适合用来确保资源(如文件)被正确释放。
方法二:使用 with 语句(推荐方式)
Python 提供了一种更加优雅的方式来管理文件——with 语句。使用 with 语句打开文件后,无论是否发生异常,文件都会在 with 代码块结束后自动关闭。
# ===== 使用 with 语句自动管理文件 =====# with语句的基本语法with open("ck_with_demo.txt", "w", encoding="utf-8") as f: f.write("使用with语句写入的第一行\n") f.write("使用with语句写入的第二行\n") # 不需要手动调用f.close(),with语句会自动关闭文件# with代码块结束后,文件已自动关闭print("文件已通过with语句自动关闭!")# 验证文件内容with open("ck_with_demo.txt", "r", encoding="utf-8") as f: print(f.read())
文件已通过with语句自动关闭!使用with语句写入的第一行使用with语句写入的第二行
💡 重要提示:with 语句是 Python 中管理资源的推荐方式。它不仅适用于文件操作,也适用于其他需要手动释放资源的场景(如数据库连接、网络连接等)。在后续的学习和实际开发中,请尽量使用 with 语句来操作文件。
关于 with 语句的更多知识(文件上下文管理器),我们将在 7.3.1 文件上下文管理器 中进一步深入学习。
【案例演示】 让我们用 with 语句重写之前的 CK 学校成绩录入案例:
# ===== 使用with语句重写成绩录入案例 =====def write_scores_with(): """使用with语句写入成绩单""" # 使用with语句打开文件,无需手动关闭 with open("ck_scores_v2.txt", "w", encoding="utf-8") as f: # 写入表头 f.write("CK学校 数字经济专业 Python课程成绩单\n") f.write("=" * 45 + "\n") f.write(f"{'学号':<10}{'姓名':<8}{'平时分':<8}{'期末分':<8}{'总评':<8}{'等级':<6}\n") f.write("-" * 45 + "\n") # 学生数据 students = [ {"id": "2025001", "name": "张三", "daily": 90, "final": 95}, {"id": "2025002", "name": "李四", "daily": 85, "final": 80}, {"id": "2025003", "name": "王五", "daily": 70, "final": 82}, {"id": "2025004", "name": "赵六", "daily": 95, "final": 98}, {"id": "2025005", "name": "钱七", "daily": 60, "final": 55}, ] for stu in students: # 计算总评成绩(平时分占40%,期末分占60%) # 回忆第2章:数值型数据的运算 total = stu["daily"] * 0.4 + stu["final"] * 0.6 total = round(total) # 回忆第2章:round()四舍五入函数 # 判断等级 if total >= 90: grade = "优秀" elif total >= 80: grade = "良好" elif total >= 70: grade = "中等" elif total >= 60: grade = "及格" else: grade = "不及格" f.write(f"{stu['id']:<10}{stu['name']:<8}{stu['daily']:<8}{stu['final']:<8}{total:<8}{grade:<6}\n") print("成绩单已写入文件(使用with语句)")# 调用函数write_scores_with()# 使用with语句读取并显示with open("ck_scores_v2.txt", "r", encoding="utf-8") as f: print("\n" + f.read())
成绩单已写入文件(使用with语句)CK学校 数字经济专业 Python课程成绩单=============================================学号姓名平时分期末分总评等级---------------------------------------------2025001张三909593优秀2025002李四858082良好2025003王五708277中等2025004赵六959897优秀2025005钱七605557不及格
💡 对比总结: 使用 with 语句相比手动调用 close() 的优势: 1. 代码更简洁:不需要手动调用 close() 2. 更安全:即使代码块中发生异常,文件也会被自动关闭 3. 更符合Python风格:with 语句是 Python 推荐的资源管理方式

三、本节知识综合案例
案例:CK 学校学生信息管理系统(文件版)
让我们将本节学到的所有知识综合起来,设计一个完整的学生信息管理案例:
# ===== CK学校学生信息管理系统(文件版) =====import osimport time# 回忆第6章:使用全局变量存储文件名DATA_FILE = "ck_students_data.txt"def init_file(): """初始化数据文件""" # 如果文件不存在,创建并写入表头 if not os.path.exists(DATA_FILE): with open(DATA_FILE, "w", encoding="utf-8") as f: f.write("CK学校 数字经济专业 学生信息表\n") f.write("=" * 55 + "\n") f.write(f"{'学号':<12}{'姓名':<8}{'性别':<6}{'年龄':<6}{'城市':<10}{'Python成绩':<10}\n") f.write("-" * 55 + "\n") print("数据文件初始化完成!") else: print("数据文件已存在。")def add_student(): """添加学生信息""" # 回忆第2章:input()函数获取用户输入 student_id = input("请输入学号:") name = input("请输入姓名:") gender = input("请输入性别:") age = input("请输入年龄:") city = input("请输入来自的城市:") score = input("请输入Python成绩:") # 使用"a"模式追加写入 with open(DATA_FILE, "a", encoding="utf-8") as f: f.write(f"{student_id:<12}{name:<8}{gender:<6}{age:<6}{city:<10}{score:<10}\n") print(f"学生 {name} 的信息已添加成功!")def show_students(): """显示所有学生信息""" try: with open(DATA_FILE, "r", encoding="utf-8") as f: content = f.read() print("\n" + content) except FileNotFoundError: print("数据文件不存在,请先初始化。")def show_file_info(): """显示文件基本信息""" if os.path.exists(DATA_FILE): size = os.path.getsize(DATA_FILE) # 回忆第2章:数值型数据的处理 size_kb = size / 1024 print(f"\n文件名:{DATA_FILE}") print(f"文件大小:{size} 字节({size_kb:.2f} KB)") print(f"文件类型:文本文件") print(f"文件路径:{os.path.abspath(DATA_FILE)}") else: print("数据文件不存在。")# 主程序def main(): """主程序""" print("=" * 55) print(" CK学校 学生信息管理系统(文件版)") print("=" * 55) while True: print("\n" + "-" * 40) print(" 1. 初始化数据文件") print(" 2. 添加学生信息") print(" 3. 查看所有学生") print(" 4. 查看文件信息") print(" 5. 退出系统") print("-" * 40) choice = input("请选择操作(1-5):") if choice == "1": init_file() elif choice == "2": add_student() elif choice == "3": show_students() elif choice == "4": show_file_info() elif choice == "5": print("\n感谢使用CK学校学生信息管理系统,再见!") break else: print("无效选项,请重新输入。")# 运行主程序main()
=======================================================CK学校 学生信息管理系统(文件版)=======================================================----------------------------------------1. 初始化数据文件2. 添加学生信息3. 查看所有学生4. 查看文件信息5. 退出系统----------------------------------------请选择操作(1-5):1数据文件初始化完成!----------------------------------------1. 初始化数据文件2. 添加学生信息3. 查看所有学生4. 查看文件信息5. 退出系统----------------------------------------请选择操作(1-5):2请输入学号:2025001请输入姓名:张三请输入性别:男请输入年龄:20请输入来自的城市:重庆请输入Python成绩:92学生 张三 的信息已添加成功!----------------------------------------1. 初始化数据文件2. 添加学生信息3. 查看所有学生4. 查看文件信息5. 退出系统----------------------------------------请选择操作(1-5):3CK学校 数字经济专业 学生信息表=======================================================学号姓名性别年龄城市Python成绩-------------------------------------------------------2025001张三男20重庆92----------------------------------------1. 初始化数据文件2. 添加学生信息3. 查看所有学生4. 查看文件信息5. 退出系统----------------------------------------请选择操作(1-5):4文件名:ck_students_data.txt文件大小:195 字节(0.19 KB)文件类型:文本文件文件路径:/home/student/ck_students_data.txt----------------------------------------1. 初始化数据文件2. 添加学生信息3. 查看所有学生4. 查看文件信息5. 退出系统----------------------------------------请选择操作(1-5):5感谢使用CK学校学生信息管理系统,再见!
💡 知识串联总结: 这个综合案例运用了本书第1章到第7章的众多知识点:
章节 | 运用的知识点 |
第1章 | import 导入模块、程序结构 |
第2章 | input() 输入、f-string 格式化、字符串对齐、os.path.getsize() |
第3章 | if-elif-else 分支、try-except 异常处理 |
第4章 | while True 循环、break 退出 |
第5章 | 列表和字典(数据组织思路) |
第6章 | 函数定义与调用、time 模块、全局变量 |
第7章 | open() 打开文件、"w"/"a"/"r" 模式、with 语句、close() 关闭文件 |

🤖 AI辅助学习小节(7.1.2)
同学们,学完7.1.2节后,如何利用AI工具来巩固和加深对本节知识的理解呢?下面是为你精心设计的AI互动练习方案!
练习一:用AI帮你生成一个”Python爱心”并保存到文件
练习目标: 综合运用文件写入操作和字符串格式化,创建一个包含爱心图案的文本文件。
AI提示词(直接复制发送给AI):
我是一个Python初学者,正在学习文件操作。请帮我完成以下任务:1. 用Python代码生成一个ASCII艺术爱心图案(用字符拼出一个大的爱心形状)2. 将这个爱心图案写入到一个名为"love.txt"的文本文件中3. 在爱心图案的上方写一行"CK学校数字经济专业",下方写一行"Python让编程更有爱"4. 使用UTF-8编码,用with语句来管理文件5. 写入完成后,读取文件内容并打印到屏幕上要求:- 爱心图案要尽量大且美观- 代码要有详细的中文注释- 使用我们学过的open()函数和文件模式
学习要点: 通过这个有趣的练习,你将巩固 with 语句、"w" 和 "r" 模式的使用,同时体验文件操作可以保存各种创意内容。

练习二:用AI帮你制作一个”重庆地铁线路图”文本文件
练习目标: 综合运用文件写入和字符串处理知识。
AI提示词(直接复制发送给AI):
请帮我用Python编写一个程序,创建一个"重庆地铁线路图"的文本文件:要求:1. 文件名为"chongqing_metro.txt"2. 用ASCII字符画出重庆地铁的3-5条主要线路(如1号线、2号线、3号线、6号线、10号线等)3. 标注重要的换乘站(如两路口、牛角沱、红旗河沟等)4. 每条线路用不同的符号或颜色标记(文本文件中可以用不同字符区分)5. 在文件末尾添加一个图例说明6. 使用with语句和UTF-8编码请让线路图尽量清晰美观,代码要有详细注释。
学习要点: 通过这个练习,你将学会如何在文件中组织复杂格式的文本内容,同时了解重庆的地铁网络。

练习三:用AI帮你创建一个”个人密码笔记本”程序
练习目标: 综合运用文件追加模式和用户交互。
AI提示词(直接复制发送给AI):
请帮我编写一个Python"密码笔记本"程序:功能要求:1. 程序启动时显示菜单:1.添加密码 2.查看所有密码 3.退出2. 选择"添加密码"时:- 提示用户输入网站/应用名称- 提示用户输入用户名- 提示用户输入密码- 将信息追加写入到"passwords.txt"文件中- 格式为:[时间] 网站: 用户名 / 密码3. 选择"查看所有密码"时:- 读取并显示文件中的所有密码记录4. 使用with语句管理文件5. 使用while循环实现菜单的反复显示要求:代码要有详细中文注释,适合初学者理解。
学习要点: 通过这个实用的练习,你将深入理解 "a" 追加模式和 "r" 读取模式的配合使用,同时复习 while 循环和分支语句。

练习四:用AI帮你生成一个”Python学习进度图表”文件
练习目标: 综合运用文件写入和之前学过的各种数据类型。
AI提示词(直接复制发送给AI):
请帮我用Python创建一个"Python学习进度图表"文本文件:要求:1. 使用字典存储各章节的学习进度(百分比)2. 用文本字符画出一个简单的水平条形图,显示每章的学习进度3. 例如:第1章 Python初步[████████████████████] 100%第2章 简单程序设计[████████████████░░░░]80%第3章 分支程序设计[████████████░░░░░░░░]60%...4. 将图表写入到"learning_progress.txt"文件中5. 在图表下方添加一行总结信息,计算总体完成进度6. 使用with语句和UTF-8编码要求:代码要有详细中文注释,条形图要美观整齐。
学习要点: 通过这个练习,你将综合运用字典、循环、字符串格式化和文件写入等多种知识,制作一个直观的学习进度可视化文件。

练习五:用AI帮你探索——“如果用不同模式打开同一个文件会怎样?”
练习目标: 通过实验深入理解不同文件打开模式的区别。
AI提示词(直接复制发送给AI):
我正在学习Python文件操作的不同模式(r, w, a, r+, w+, a+)。请帮我设计一组对比实验:要求:1. 先创建一个初始文件"experiment.txt",内容为"原始内容ABC"2. 然后分别用以下模式打开文件并进行操作,每次操作后都打印文件内容:a. 用"w"模式写入"新内容XYZ",查看文件内容b. 重新创建初始文件,用"a"模式追加"追加内容DEF",查看文件内容c. 重新创建初始文件,用"r+"模式读取后写入"追加GHI",查看文件内容3. 每次实验前都重新创建初始文件,确保实验条件一致4. 在每个实验步骤中添加详细的注释,解释发生了什么5. 最后给出一个总结表格,对比各种模式的行为差异请让实验步骤清晰,注释详细,帮助我真正理解这些模式的区别。
学习要点: 通过这组对比实验,你将深入理解不同文件模式的行为差异,特别是 "w" 的覆盖特性和 "a" 的追加特性。

📝 自学检查清单
完成以上AI辅助练习后,请对照以下清单检查自己的掌握情况:
☐我能正确使用 open() 函数打开文件,并指定正确的模式
☐我能说出 "r"、"w"、"a" 三种基本模式的区别
☐我知道 "w" 模式会清空文件原有内容,使用时会格外小心
☐我能使用 "r+"、"w+"、"a+" 组合模式
☐我能解释为什么要关闭文件(close())
☐我能使用 with 语句来安全地管理文件
☐我能结合 try-except 处理文件操作中的异常
☐我能综合运用文件操作和之前学过的知识(分支、循环、函数等)编写完整的程序

📚 本节知识点总结
7.1 文件基本知识│├── 7.1.1 文件概述│├── 文件的概念:存储在外存上的数据集合│├── 文件的类型││├── 文本文件:以字符编码存储(.txt, .py, .csv等)││└── 二进制文件:以二进制编码存储(.png, .mp3, .pdf等)│├── 文件名:主文件名 + 扩展名│├── 文件路径││├── 绝对路径:从根目录开始的完整路径││└── 相对路径:相对于当前工作目录的路径│└── 文件的两种操作:读(输入)和写(输出)│└── 7.1.2 文件的打开与关闭├── 打开文件:open(file, mode, encoding)│├── "r":只读模式(默认)│├── "w":只写模式(覆盖写入)│├── "a":追加模式(末尾追加)│├── "+":读写组合模式│└── "b":二进制模式└── 关闭文件:close()├── 手动关闭:f.close()├── try-finally确保关闭└── with语句自动关闭(推荐)
