Python 系列(四十六) 使用 open() 读取和写入文件
1 | 作者:李晓辉 |
- Python 系列(一) 从零开始认识 Python,入门其实没那么难
- Python 系列(二) 学 Python 的第一步,把开发环境搭建好
- Python 系列(三) 基础语法避坑指南,缩进、大小写、续行与注释
- Python 系列(四) Python 输入输出详解,print()、input() 与常见避坑指南
- Python 系列(五) 数值类型与运算符详解,整除、浮点精度与进制转换实战
- Python 系列(六) 字符串处理实战,查找、替换、切片与日志分析
- Python 系列(七) 类型转换详解,int()、float()、str() 与金额计算避坑
- Python 系列(八) Python 流程控制入门,掌握 if、elif 和 else
- Python 系列(九) Python 逻辑运算符详解,and、or、not 一篇搞懂
- Python 系列(十) while、for 循环实战,彻底搞懂 range、break 与 continue
- Python 系列(十一) list、tuple、set、dict,到底该怎么选?
- Python 系列(十二) List 列表实战,搞定数据增删改查与批量处理
- Python 系列(十三) Tuple 元组实战,搞懂不可变特性与 enumerate() 遍历
- Python 系列(十四) Set 集合实战,搞定数据去重与集合运算
- Python 系列(十五) Dict 字典详解,掌握快速查找与键值操作
- Python 系列(十六) sort() 和 sorted() 详解,掌握数据排序技巧
- Python 系列(十七) 自定义函数入门,让重复代码一次编写多次使用
- Python 系列(十八) 函数参数详解,搞懂位置参数、关键字参数和默认参数
- Python 系列(十九) 从 *args 到 **kwargs,让函数调用更灵活
- Python 系列(二十) 变量作用域是什么?一文搞懂 global 和 nonlocal
- Python 系列(二十一) 搞懂变量、对象和引用,理解函数参数传递机制
- Python 系列(二十二) map() 和 filter() 详解,轻松实现批量数据处理与筛选
- Python 系列(二十三) 嵌套函数与 lambda 表达式详解,搞懂作用域与闭包
- Python 系列(二十四) 搞懂递归函数,从基线条件到实际应用
- Python 系列(二十五) 聊聊模块与 import,让代码告别重复编写
- Python 系列(二十六) Python 模块入门,从 import 到模块复用
- Python 系列(二十七) Python dir() 函数详解,快速查看模块中的函数与属性
- Python 系列(二十八) 不会用 Python 标准库?教你快速查找模块和函数
- Python 系列(二十九) 搞懂 Python sys 模块,让脚本更适合自动化运维
- Python 系列(三十) 为什么 0.1 + 0.2 不等于 0.3?彻底搞懂 Decimal
- Python 系列(三十一) 搞懂 datetime 日期时间,轻松处理时区与时间计算
- Python 系列(三十二) 面向对象编程入门,从零理解类、对象、封装与继承
- Python 系列(三十三) 什么是类和对象?零基础理解 Python class
- Python 系列(三十四) Python 属性详解,搞懂类属性、实例属性和 setter
- Python 系列(三十五) 学会特殊方法,让对象打印出你想要的内容
- Python 系列(三十六) 多个对象如何共享数据?彻底搞懂类变量
- Python 系列(三十七) 搞懂父类、子类和方法重写,真正理解继承与多态
- Python 系列(三十八) 如何判断数据类型?三个内置函数一次讲明白
- Python 系列(三十九) 搞懂异常模型与常见异常类型,读懂程序报错
- Python 系列(四十) 从零学会异常处理,掌握 try、except、else 和 finally
- Python 系列(四十一) ValueError、TypeError 到底是什么?一文搞懂常见异常
- Python 系列(四十二) ValueError、TypeError 到底是什么?一文搞懂常见异常
- Python 系列(四十三) 别只会处理异常!学会自定义异常,让程序更容易维护
- Python 系列(四十四) 从零认识 assert 断言,让程序学会检查自己
- Python 系列(四十五) 使用 sys 模块处理标准输入与输出
- Python 系列(四十六) 使用 open() 读取和写入文件
- Python 系列(四十七) 学会读写文本文件,让程序保存运行结果
- Python 系列(四十八) 搞懂 bytes、bytearray 和二进制读写
- Python 系列(四十九) 使用 seek() 和 tell() 灵活控制文件读取位置
- Python 系列(五十) 掌握 os 和 os.path,实现文件与目录自动化管理
- Python 系列(五十一) 掌握列表推导式,轻松实现列表生成与数据筛选
- Python 系列(五十二) 掌握字典推导式,让字典创建更简单
- Python 系列(五十三) 从零理解生成器,轻松处理大量数据
- Python 系列(五十五) 使用 zip() 同时遍历多个集合
前面我们学习了如何使用 input() 接收用户输入,以及使用 print() 在屏幕上显示内容。我们还了解了 sys.stdin、sys.stdout 和 sys.stderr,知道 Python 可以通过不同的输入、输出通道读取和显示数据。
但是,这些操作还存在一个问题:程序运行结束后,如果没有主动保存数据,下次运行时,我们通常无法直接取回上一次处理的结果。
假设你是一名 Linux 运维工程师,每天需要检查服务器的运行状态。通过 Python 获取了 CPU 使用率、内存使用情况和磁盘空间后,你希望把这些信息保存下来,以便第二天查看,或者在服务器出现故障时追溯之前的运行情况。
如果每次都只能在屏幕上查看结果,就很难长期保存和分析这些信息。
这时候,我们就需要学习文件操作。
Python 可以将数据写入文件,也可以从文件中读取数据。而在学习具体的读写方法之前,我们需要先理解一个重要概念:数据流。
为什么需要数据流
先想象一个简单的场景。
你需要把一段文字从 Python 程序保存到磁盘上的文件中。数据并不是凭空出现在文件里的,而是需要经过一个读写过程。
同样,当你希望读取文件中的内容时,Python 也需要从文件中获取数据,再交给程序处理。
这个过程可以简单理解为:
flowchart LR
A[Python 程序] -->|写入数据| B[文件]
B -->|读取数据| A这里的文件可以是普通的文本文件、日志文件,也可以是其他类型的文件。
那么,数据流究竟是什么?
我们可以把数据流理解为:程序与数据来源或目标之间进行数据传输的一种方式。
例如:
- 使用
input()获取用户输入,是程序从输入通道接收数据。 - 使用
print()显示结果,是程序向输出通道发送数据。 - 使用文件操作读取日志,是程序从文件中获取数据。
- 使用文件操作保存检查结果,是程序向文件写入数据。
数据流并不意味着数据一定要通过网络传输。即使数据只是在 Python 程序和本地文件之间传递,也可以通过数据流的方式进行处理。
使用 open() 打开文件
在 Python 中,如果希望读取或写入文件,通常需要先调用内置函数 open()。
例如,我们先创建一个名为 file.txt 的文件,并向其中写入内容:
1 | f = open("file.txt", "w") |
这行代码看起来很短,但其中包含几个需要理解的知识点。
理解 open() 函数
open() 是 Python 内置的文件操作函数,不需要额外安装模块,就可以直接使用。
它的基本语法如下:
1 | open(file, mode) |
这里先认识两个参数:
| 参数 | 作用 |
|---|---|
file | 指定要打开的文件名或文件路径 |
mode | 指定打开文件的方式,例如读取或写入 |
例如:
1 | open("file.txt", "w") |
其中,file.txt 是文件名,w 表示以写入模式打开文件。
如果只写文件名而没有指定目录,Python 通常会在程序的当前工作目录中查找或创建这个文件。
需要注意,当前工作目录不一定就是 Python 脚本所在的目录。后续遇到文件找不到的问题时,我们还需要学习如何确认程序的当前工作目录。
理解文件对象
再来看下面这行代码:
1 | f = open("file.txt", "w") |
执行这行代码后,Python 会打开文件,并返回一个文件对象。
我们把这个文件对象赋值给变量 f,后续就可以通过 f 对文件进行读写操作。
可以把它理解为:open() 负责打开文件,而 f 保存了程序操作这个文件所需要的对象。
例如:
1 | f = open("file.txt", "w") |
在常见的 Python 环境中,输出内容类似下面这样:
1 | <_io.TextIOWrapper name='file.txt' mode='w' encoding='utf-8'> |
具体输出可能因 Python 版本和运行环境而有所不同。
这里的 TextIOWrapper 是 Python 用来处理文本文件的对象类型之一。现在不需要记住这个名称,只需要知道:f 不是文件里的文字,而是一个可以用来操作文件的对象。
认识常见的文件打开模式
open() 的第二个参数 mode 决定了 Python 打开文件后可以进行什么操作。
初学阶段,先认识下面几种常见模式即可。
| 模式 | 含义 | 文件不存在时 | 文件已存在时 |
|---|---|---|---|
r | 读取文件 | 报错 | 读取原有内容 |
w | 写入文件 | 创建文件 | 清空原有内容 |
a | 追加内容 | 创建文件 | 保留原有内容,在末尾追加 |
x | 创建新文件 | 创建文件 | 报错,不覆盖原文件 |
r+ | 读取并写入 | 报错 | 不会自动清空文件 |
这里有一个特别重要的注意事项。
使用 w 模式打开一个已经存在的文件时,文件原有内容会被清空。
例如,假设 file.txt 原本保存着以下内容:
1 | 服务器:web01 |
执行下面的代码:
1 | f = open("file.txt", "w") |
即使我们还没有写入任何新内容,文件原来的内容也已经被清空了。
因此,在实际运维脚本中,如果只是希望不断记录新的检查结果,通常应该考虑使用 a 模式,而不是直接使用 w 模式。
尝试向文件写入内容
了解了文件对象和打开模式后,我们来完成一个可以实际运行的例子。
创建 Python 脚本
在一个方便查找的目录中创建 write_file.py,输入下面的代码:
1 | f = open("file.txt", "w") |
这段代码包含三个步骤:
open("file.txt", "w"):以写入模式打开文件。如果文件不存在,就创建文件。f.write("Hello, Python!\n"):向文件写入一行文字。f.close():关闭文件,结束这次文件操作。
这里的 \n 表示换行符。它可以让后续写入的内容从下一行开始。
write() 是文件对象提供的方法,用来向文件写入数据。对于以文本模式打开的文件,它接收的是字符串。
close() 则用于关闭文件对象。关闭文件可以让 Python 完成必要的收尾工作,并释放相关资源。
运行程序
打开终端,进入 write_file.py 所在的目录,然后执行:
1 | python write_file.py |
如果你的系统使用 python3 命令启动 Python,也可以执行:
1 | python3 write_file.py |
程序正常运行时,通常不会显示任何内容。这并不代表程序没有执行,而是因为我们没有使用 print() 输出信息。
此时,当前工作目录下应该出现一个名为 file.txt 的文件。
打开文件,可以看到:
1 | Hello, Python! |
恭喜你!你已经完成了第一次 Python 文件写入操作。
使用 read() 读取文件内容
既然可以把内容写入文件,那么接下来就试试把它读取出来。
创建一个名为 read_file.py 的文件,写入以下代码:
1 | f = open("file.txt", "r") |
我们逐步解释这段代码。
open("file.txt", "r") 表示以读取模式打开文件。此时,文件必须存在,否则 Python 会报告文件不存在的错误。
f.read() 用于读取文件内容,并将读取到的内容作为字符串返回。
1 | content = f.read() |
这行代码把读取到的内容保存到变量 content 中。
接下来:
1 | print(content) |
我们使用 print() 将读取到的内容显示在终端上。
运行程序:
1 | python read_file.py |
预期输出:
1 | Hello, Python! |
至此,我们已经掌握了文件读写的基本流程:
flowchart TD
A[开始] --> B[调用 open() 打开文件]
B --> C{选择操作模式}
C -->|读取模式 r| D[调用 read() 读取内容]
C -->|写入模式 w| E[调用 write() 写入内容]
D --> F[处理或显示数据]
E --> G[完成数据写入]
F --> H[关闭文件]
G --> H
H --> I[结束]不过,上面的代码还存在一个问题:如果程序在文件操作过程中发生异常,close() 就可能无法正常执行。
在实际开发中,我们通常会使用更安全的文件打开方式。
使用 with 自动管理文件
Python 提供了 with 语句,可以帮助我们管理文件对象的生命周期。
先看一个例子:
1 | with open("file.txt", "w") as f: |
这段代码与之前的写入示例类似,但不再需要显式调用 f.close()。
当程序离开 with 代码块时,Python 会自动关闭文件,即使代码块执行过程中发生异常,也能正常执行相应的资源清理操作。
这里的 as f 表示把打开后得到的文件对象赋值给变量 f。
另外,with 语句下面的代码必须按照 Python 的语法要求缩进。这里的 f.write() 前面有四个空格,表示它属于 with 代码块。
我们也可以使用相同的方式读取文件:
1 | with open("file.txt", "r") as f: |
这样就不需要自己调用 close()。
在实际编写 Python 程序时,建议优先使用 with open(...) 管理文件,而不是手动调用 open() 和 close()。
将文件写入与读取结合起来
现在,我们把前面学到的知识组合起来,编写一个简单的服务器检查记录程序。
创建 server_check.py:
1 | # 将服务器检查结果保存到文件 |
运行程序:
1 | python server_check.py |
预期输出:
1 | 服务器名称:web01 |
同时,程序还会在当前工作目录下生成 server_check.txt,把这三条检查记录保存下来。
这个例子虽然简单,却已经包含了实际自动化脚本经常使用的几个步骤:
- 生成需要保存的数据。
- 打开文件并写入内容。
- 重新打开文件并读取内容。
- 将读取到的数据交给程序进一步处理。
需要注意,这里使用的是 w 模式,因此每次重新运行程序,原来的检查记录都会被新内容覆盖。如果想保留每次运行的记录,可以把写入模式改为 a,让新内容追加到文件末尾。
本篇小结
通过本篇学习,我们认识了 Python 文件操作的基本概念。
- 数据流可以帮助程序与文件等数据来源或目标进行数据传输。
open()用于打开文件,并返回文件对象。r、w、a和x是几种常见的文件打开模式。read()用于读取文件内容,write()用于写入内容。with open(...)可以帮助我们自动管理文件的关闭。
不过,到目前为止,我们只是初步认识了文件操作。实际使用时,文本编码、文件路径、换行符、逐行读取以及大文件处理等问题,都值得进一步学习。
下一篇,我们将正式进入文本文件的读取与写入,深入了解 Python 如何处理文本内容,以及如何更可靠地读取和保存文件。
