feat(python进阶): 新增文件与目录操作课程

This commit is contained in:
2026-08-03 22:01:22 +08:00
parent 691405f380
commit f7c820b0f4
5 changed files with 538 additions and 13 deletions

View File

@@ -0,0 +1,405 @@
# 第 2-2 课:文件与目录操作
## 一、本课目标
完成本课后,你将能够:
1. 解释文件、目录和路径分别是什么;
2. 使用 `Path` 表示和组合路径;
3. 创建练习目录;
4. 安全地写入、追加和读取文本文件;
5. 检查路径是否存在,以及它是不是文件;
6. 遍历目录中的文件;
7. 说明文件操作可能带来的副作用。
## 二、前置知识
学习本课前,需要掌握:
- 字符串、变量和布尔值;
- 条件判断与循环;
- 函数、参数和返回值;
- 模块、导入和程序入口判断。
上一课学习了模块。本课将从 Python 标准库中导入 `pathlib` 模块提供的 `Path`
## 三、文件、目录和路径是什么
文件File是保存在计算机中的一份数据例如
- Python 程序 `practice.py`
- 文本文件 `learning_notes.txt`
- 图片文件 `photo.png`
目录Directory也常被称为文件夹用于组织文件和其他目录。
路径Path用于描述文件或目录在计算机中的位置。例如
```text
02_python进阶/2_2_文件与目录操作/runtime_data/learning_notes.txt
```
可以把路径理解为从一个位置找到目标文件所经过的路线。
## 四、为什么使用 `Path`
不同操作系统表示路径的方式可能不同。Windows 常见反斜杠 `\`,其他系统常见正斜杠 `/`。手工拼接路径容易写错。
`pathlib` 是 Python 标准库中的路径处理模块。`Path` 是它提供的路径对象:
```python
from pathlib import Path
lesson_dir = Path(__file__).parent
data_dir = lesson_dir / "runtime_data"
```
对象Object可以暂时理解为“同时保存数据和操作能力的值”。面向对象课程会详细讲解。
这里:
- `__file__` 是 Python 自动提供的特殊变量,表示当前文件的位置;
- `Path(__file__)` 把位置转换成路径对象;
- `.parent` 得到当前文件所在的目录;
- `/ "runtime_data"` 在原路径后面组合新的目录名。
这里的 `/` 不是数学除法。`Path` 对象把它设计成了清晰的路径组合写法。
## 五、相对路径与绝对路径
相对路径Relative Path表示相对于当前工作位置的路线
```text
runtime_data/learning_notes.txt
```
绝对路径Absolute Path从磁盘或系统根位置开始完整描述目标位置。在 Windows 中可能类似:
```text
F:\PyCharm\PythonLearn\02_python进阶\2_2_文件与目录操作
```
本课通过 `Path(__file__).parent` 取得课程目录。这样无论从项目根目录还是课程目录启动示例,数据都会写入本课自己的 `runtime_data`
## 六、创建目录
```python
data_dir.mkdir(parents=True, exist_ok=True)
```
`mkdir()` 表示创建目录:
- `parents=True`:需要时一并创建缺少的上级目录;
- `exist_ok=True`:目录已经存在时不报错。
如果没有 `exist_ok=True`,第二次运行程序时可能出现:
```text
FileExistsError
```
中文解释:程序想创建的文件或目录已经存在。
## 七、写入文本文件
```python
notes_file.write_text(
"第一条:学习使用 Path 表示路径。\n",
encoding="utf-8",
)
```
`write_text()` 会创建文件并写入文本。如果文件已经存在,它会覆盖原有内容。
覆盖意味着旧内容会被替换,可能难以恢复。因此:
- 练习时只操作专用数据目录;
- 写入前确认路径是否正确;
- 不要把重要文件路径交给练习程序;
- 中文文本明确使用 `encoding="utf-8"`
编码Encoding是文字与计算机数据之间的转换规则。UTF-8 是常用的文字编码,可以保存中文和多种语言。
字符串中的 `\n` 表示换行。
## 八、追加文本文件
覆盖写入会清空旧内容。希望在文件末尾增加内容时,可以使用追加模式:
```python
with notes_file.open("a", encoding="utf-8") as file:
file.write("第二条:学习读取和追加文件。\n")
```
打开模式File Mode`"a"` 中的字母来自 append表示追加。
`with` 语句会在代码块结束后帮助关闭文件。即使以后文件操作发生错误,也更容易正确释放文件资源。
本课先记住固定结构:
```python
with path.open("a", encoding="utf-8") as file:
file.write("需要追加的内容")
```
## 九、读取文本文件
```python
content = notes_file.read_text(encoding="utf-8")
print(content)
```
`read_text()` 会读取整个文本文件,并返回一个字符串。
如果文件不存在,可能出现:
```text
FileNotFoundError
```
中文解释Python 在指定路径没有找到需要读取的文件。
可以先检查文件是否存在:
```python
if notes_file.exists():
content = notes_file.read_text(encoding="utf-8")
```
## 十、检查路径
常用检查方法:
```python
path.exists()
path.is_file()
path.is_dir()
```
- `exists()`:路径是否存在;
- `is_file()`:路径是否存在并且是文件;
- `is_dir()`:路径是否存在并且是目录。
这些方法返回布尔值 `True``False`,可以与条件判断配合使用。
## 十一、遍历目录
```python
for path in data_dir.iterdir():
if path.is_file():
print(path.name)
```
`iterdir()` 会提供目录中的每一项。每一项仍然是 `Path` 对象:
- `path.name` 表示文件或目录的名称;
- `path.is_file()` 判断它是否是文件。
本课只遍历当前目录,不递归进入更深层目录。递归表示一个操作继续处理内部的子目录,属于后续扩展内容。
## 十二、示例文件与数据影响
本课文件结构:
```text
02_python进阶/2_2_文件与目录操作/
├── .gitignore
├── README.md
├── file_directory_example.py
└── practice.py
```
运行示例后会产生:
```text
runtime_data/
└── learning_notes.txt
```
运行练习后应产生:
```text
practice_data/
└── diary.txt
```
这两个数据目录都被本课 `.gitignore` 忽略,不会加入 Git。程序不会操作课程目录之外的文件。
每次运行完整示例时,`learning_notes.txt` 会先被写入初始内容,再追加第二条记录,因此结果不会无限重复增加。
## 十三、运行方法
在 PowerShell 中进入项目根目录:
```powershell
cd F:\PyCharm\PythonLearn
```
运行完整示例:
```powershell
python .\02_python进阶\2_2_文件与目录操作\file_directory_example.py
```
完成练习后运行:
```powershell
python .\02_python进阶\2_2_文件与目录操作\practice.py
```
## 十四、运行结果
完整示例的预期结果类似:
```text
数据目录已准备runtime_data
初始内容已写入learning_notes.txt
新的学习记录已追加。
学习记录内容:
第一条:学习使用 Path 表示路径。
第二条:学习读取和追加文件。
数据目录中的文件:
- learning_notes.txt
```
然后可以打开 `runtime_data/learning_notes.txt`,确认文件内容与终端输出一致。
## 十五、关键代码执行顺序
运行 `file_directory_example.py` 时:
1. 导入 `Path`
2. 根据当前文件位置准备课程目录、数据目录和文件路径;
3. 定义文件操作函数;
4. 入口判断成立,调用 `main()`
5. 创建 `runtime_data`
6. 覆盖写入初始记录;
7. 在文件末尾追加一条记录;
8. 读取并输出完整内容;
9. 遍历数据目录并输出文件名。
先创建目录再写文件非常重要。目录不存在时,直接写入内部文件会失败。
## 十六、常见错误
### 16.1 手工拼接路径
不推荐:
```python
file_path = lesson_dir + "/runtime_data/notes.txt"
```
`lesson_dir``Path` 对象,不能直接与普通字符串这样相加。使用:
```python
file_path = lesson_dir / "runtime_data" / "notes.txt"
```
### 16.2 忘记创建目录
`runtime_data` 不存在时直接写入内部文件,会出现 `FileNotFoundError`。应先调用 `mkdir()`
### 16.3 忘记指定中文编码
读取或写入中文时未指定 UTF-8可能出现乱码或编码错误。请在读写两端都使用 `encoding="utf-8"`
### 16.4 混淆覆盖和追加
- `write_text()` 会覆盖原内容;
- `open("a")` 会在末尾追加内容。
操作重要文件前必须确认自己需要哪一种行为。
### 16.5 忘记关闭文件
手动调用 `open()` 后如果忘记关闭文件,可能造成资源占用。本课使用 `with` 自动管理文件。
### 16.6 路径指向项目外部
练习时不要使用系统目录、桌面文件或其他项目文件。把所有练习数据限制在本课的 `practice_data` 中。
## 十七、课堂练习
打开 `practice.py`,依次完成:
1. 准备练习目录和日记文件路径;
2. 创建 `practice_data`
3. 写入第一条日记;
4. 追加第二条日记;
5. 读取并输出完整内容;
6. 检查文件是否存在并遍历目录。
每完成一部分就运行一次。不要直接复制参考答案。
## 十八、参考答案
请先独立完成练习,再展开查看。
<details>
<summary>查看参考答案</summary>
```python
from pathlib import Path
lesson_dir = Path(__file__).parent
practice_dir = lesson_dir / "practice_data"
diary_file = practice_dir / "diary.txt"
practice_dir.mkdir(parents=True, exist_ok=True)
print("练习目录已准备。")
first_entry = "今天学习了文件与目录。\n"
diary_file.write_text(first_entry, encoding="utf-8")
print("日记已写入。")
with diary_file.open("a", encoding="utf-8") as file:
file.write("我会使用 Path 处理路径。\n")
print("日记已追加。")
content = diary_file.read_text(encoding="utf-8")
print("日记内容:")
print(content, end="")
if diary_file.exists():
print("日记文件存在。")
print("练习目录中的文件:")
for path in practice_dir.iterdir():
if path.is_file():
print(path.name)
```
</details>
## 十九、本课小结
- 文件保存数据,目录用于组织文件,路径描述它们的位置;
- `Path` 可以清晰地表示和组合路径;
- `mkdir()` 可以创建目录;
- `write_text()` 可以写入文本,但会覆盖原内容;
- `open("a")` 可以追加内容;
- `read_text()` 可以读取整个文本文件;
- `with` 可以帮助正确关闭文件;
- `exists()``is_file()``is_dir()` 可以检查路径;
- `iterdir()` 可以遍历目录;
- 文件操作存在副作用,必须限制操作范围并确认目标路径。
## 二十、验收标准
完成本课时,应满足:
- 可以解释文件、目录、相对路径和绝对路径;
- 可以使用 `Path(__file__).parent` 定位当前课程目录;
- 可以使用 `/` 组合 `Path` 路径;
- 可以创建已经存在也不会报错的目录;
- 可以正确写入、追加和读取中文文本;
- 可以解释覆盖写入与追加写入的区别;
- 可以使用 `with` 打开文件;
- 可以检查路径并遍历目录中的文件;
- 练习数据只出现在 `practice_data` 中;
- 运行两次练习,程序都不会崩溃;
- 最终日记内容不会因为重复运行而无限增加。