Files

406 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第 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` 中;
- 运行两次练习,程序都不会崩溃;
- 最终日记内容不会因为重复运行而无限增加。