1
2
3
4
5
6
7
作者:李晓辉

联系方式:

1. 微信:Lxh_Chat

2. 邮箱:939958092@qq.com
  1. Python 系列(一) 从零开始认识 Python,入门其实没那么难
  2. Python 系列(二) 学 Python 的第一步,把开发环境搭建好
  3. Python 系列(三) 基础语法避坑指南,缩进、大小写、续行与注释
  4. Python 系列(四) Python 输入输出详解,print()、input() 与常见避坑指南
  5. Python 系列(五) 数值类型与运算符详解,整除、浮点精度与进制转换实战
  6. Python 系列(六) 字符串处理实战,查找、替换、切片与日志分析
  7. Python 系列(七) 类型转换详解,int()、float()、str() 与金额计算避坑
  8. Python 系列(八) Python 流程控制入门,掌握 if、elif 和 else
  9. Python 系列(九) Python 逻辑运算符详解,and、or、not 一篇搞懂
  10. Python 系列(十) while、for 循环实战,彻底搞懂 range、break 与 continue
  11. Python 系列(十一) list、tuple、set、dict,到底该怎么选?
  12. Python 系列(十二) List 列表实战,搞定数据增删改查与批量处理
  13. Python 系列(十三) Tuple 元组实战,搞懂不可变特性与 enumerate() 遍历
  14. Python 系列(十四) Set 集合实战,搞定数据去重与集合运算
  15. Python 系列(十五) Dict 字典详解,掌握快速查找与键值操作
  16. Python 系列(十六) sort() 和 sorted() 详解,掌握数据排序技巧
  17. Python 系列(十七) 自定义函数入门,让重复代码一次编写多次使用
  18. Python 系列(十八) 函数参数详解,搞懂位置参数、关键字参数和默认参数
  19. Python 系列(十九) 从 *args 到 **kwargs,让函数调用更灵活
  20. Python 系列(二十) 变量作用域是什么?一文搞懂 global 和 nonlocal
  21. Python 系列(二十一) 搞懂变量、对象和引用,理解函数参数传递机制
  22. Python 系列(二十二) map() 和 filter() 详解,轻松实现批量数据处理与筛选
  23. Python 系列(二十三) 嵌套函数与 lambda 表达式详解,搞懂作用域与闭包
  24. Python 系列(二十四) 搞懂递归函数,从基线条件到实际应用
  25. Python 系列(二十五) 聊聊模块与 import,让代码告别重复编写
  26. Python 系列(二十六) Python 模块入门,从 import 到模块复用
  27. Python 系列(二十七) Python dir() 函数详解,快速查看模块中的函数与属性
  28. Python 系列(二十八) 不会用 Python 标准库?教你快速查找模块和函数
  29. Python 系列(二十九) 搞懂 Python sys 模块,让脚本更适合自动化运维
  30. Python 系列(三十) 为什么 0.1 + 0.2 不等于 0.3?彻底搞懂 Decimal
  31. Python 系列(三十一) 搞懂 datetime 日期时间,轻松处理时区与时间计算
  32. Python 系列(三十二) 面向对象编程入门,从零理解类、对象、封装与继承
  33. Python 系列(三十三) 什么是类和对象?零基础理解 Python class
  34. Python 系列(三十四) Python 属性详解,搞懂类属性、实例属性和 setter
  35. Python 系列(三十五) 学会特殊方法,让对象打印出你想要的内容
  36. Python 系列(三十六) 多个对象如何共享数据?彻底搞懂类变量
  37. Python 系列(三十七) 搞懂父类、子类和方法重写,真正理解继承与多态
  38. Python 系列(三十八) 如何判断数据类型?三个内置函数一次讲明白
  39. Python 系列(三十九) 搞懂异常模型与常见异常类型,读懂程序报错
  40. Python 系列(四十) 从零学会异常处理,掌握 try、except、else 和 finally
  41. Python 系列(四十一) ValueError、TypeError 到底是什么?一文搞懂常见异常
  42. Python 系列(四十二) ValueError、TypeError 到底是什么?一文搞懂常见异常
  43. Python 系列(四十三) 别只会处理异常!学会自定义异常,让程序更容易维护
  44. Python 系列(四十四) 从零认识 assert 断言,让程序学会检查自己
  45. Python 系列(四十五) 使用 sys 模块处理标准输入与输出
  46. Python 系列(四十六) 使用 open() 读取和写入文件
  47. Python 系列(四十七) 学会读写文本文件,让程序保存运行结果
  48. Python 系列(四十八) 搞懂 bytes、bytearray 和二进制读写
  49. Python 系列(四十九) 使用 seek() 和 tell() 灵活控制文件读取位置
  50. Python 系列(五十) 掌握 os 和 os.path,实现文件与目录自动化管理
  51. Python 系列(五十一) 掌握列表推导式,轻松实现列表生成与数据筛选
  52. Python 系列(五十二) 掌握字典推导式,让字典创建更简单
  53. Python 系列(五十三) 从零理解生成器,轻松处理大量数据
  54. 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
2
3
f = open("file.txt", "w")

print(f)

在常见的 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
2
服务器:web01
CPU 使用率:35%

执行下面的代码:

1
f = open("file.txt", "w")

即使我们还没有写入任何新内容,文件原来的内容也已经被清空了。

因此,在实际运维脚本中,如果只是希望不断记录新的检查结果,通常应该考虑使用 a 模式,而不是直接使用 w 模式。

尝试向文件写入内容

了解了文件对象和打开模式后,我们来完成一个可以实际运行的例子。

创建 Python 脚本

在一个方便查找的目录中创建 write_file.py,输入下面的代码:

1
2
3
4
5
f = open("file.txt", "w")

f.write("Hello, Python!\n")

f.close()

这段代码包含三个步骤:

  • 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
2
3
4
5
6
7
f = open("file.txt", "r")

content = f.read()

print(content)

f.close()

我们逐步解释这段代码。

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
2
with open("file.txt", "w") as f:
f.write("Hello, Python!\n")

这段代码与之前的写入示例类似,但不再需要显式调用 f.close()。

当程序离开 with 代码块时,Python 会自动关闭文件,即使代码块执行过程中发生异常,也能正常执行相应的资源清理操作。

这里的 as f 表示把打开后得到的文件对象赋值给变量 f。

另外,with 语句下面的代码必须按照 Python 的语法要求缩进。这里的 f.write() 前面有四个空格,表示它属于 with 代码块。

我们也可以使用相同的方式读取文件:

1
2
3
with open("file.txt", "r") as f:
content = f.read()
print(content)

这样就不需要自己调用 close()。

在实际编写 Python 程序时,建议优先使用 with open(...) 管理文件,而不是手动调用 open() 和 close()。

将文件写入与读取结合起来

现在,我们把前面学到的知识组合起来,编写一个简单的服务器检查记录程序。

创建 server_check.py:

1
2
3
4
5
6
7
8
9
10
11
12
# 将服务器检查结果保存到文件
with open("server_check.txt", "w") as f:
f.write("服务器名称:web01\n")
f.write("CPU 使用率:35%\n")
f.write("内存使用率:62%\n")

# 读取文件中的检查结果
with open("server_check.txt", "r") as f:
content = f.read()

# 在终端显示检查结果
print(content)

运行程序:

1
python server_check.py

预期输出:

1
2
3
服务器名称:web01
CPU 使用率:35%
内存使用率:62%

同时,程序还会在当前工作目录下生成 server_check.txt,把这三条检查记录保存下来。

这个例子虽然简单,却已经包含了实际自动化脚本经常使用的几个步骤:

  • 生成需要保存的数据。
  • 打开文件并写入内容。
  • 重新打开文件并读取内容。
  • 将读取到的数据交给程序进一步处理。

需要注意,这里使用的是 w 模式,因此每次重新运行程序,原来的检查记录都会被新内容覆盖。如果想保留每次运行的记录,可以把写入模式改为 a,让新内容追加到文件末尾。

本篇小结

通过本篇学习,我们认识了 Python 文件操作的基本概念。

  • 数据流可以帮助程序与文件等数据来源或目标进行数据传输。
  • open() 用于打开文件,并返回文件对象。
  • r、w、a 和 x 是几种常见的文件打开模式。
  • read() 用于读取文件内容,write() 用于写入内容。
  • with open(...) 可以帮助我们自动管理文件的关闭。

不过,到目前为止,我们只是初步认识了文件操作。实际使用时,文本编码、文件路径、换行符、逐行读取以及大文件处理等问题,都值得进一步学习。

下一篇,我们将正式进入文本文件的读取与写入,深入了解 Python 如何处理文本内容,以及如何更可靠地读取和保存文件。