文件操作
约 2882 字大约 10 分钟
2025-04-04
我们编写的程序在运行过程中,中间数据和最终结果通常存储在内存中。然而,当程序终止后,这些数据也会随之消失。但很多时候,我们需要将获取的数据保存下来,以供日后使用。如果能将内存中的中间数据转移到硬盘上存储,那么当下次程序再次运行时,就可以调用之前保存的结果。这就涉及到 Python 中的文件操作
- 文件操作初识
- 文件操作模式
- 文件操作步骤
- 文件路径
- 1所有文件操作都用 with open(...) as f:忘记 close 是新手最常见的资源泄漏。
- 2对同一个文件分别用 r、w、a 试一次,体会 w 会清空、a 永远追加在末尾。
- 3处理文本永远显式写 encoding='utf-8',否则 Windows 默认 gbk、Linux 默认 utf-8,跨平台时必出乱码。
- 4大文件别一次 f.read(),用 for line in f 逐行处理 —— 内存稳定 O(1)。
- 5二进制(如图片)用 rb/wb 模式且不传 encoding,文本和字节是两套世界。
文件操作初识
我们编写的程序在运行过程中,中间数据和最终结果通常存储在内存中。然而,当程序终止后,这些数据也会随之消失。但很多时候,我们需要将获取的数据保存下来,以供日后使用。如果能将内存中的中间数据转移到硬盘上存储,那么当下次程序再次运行时,就可以调用之前保存的结果。这就涉及到 Python 中的文件操作
文件操作模式
常用的文件操作模式共有九种:
r:只读文本w:清空写文本a:追加写文本(非常重要)rb:只读字节(可应用于爬虫)wb:清空写字节ab:追加写字节(非常重要)r+:读写模式(重要)w+:清空写读模式a+:追加写读模式
文件操作步骤
进行文件操作时,通常需要完成以下四个准备工作:
- 找到文件的路径;
- 确定文件的操作模式;
- 设置文件的编码方式;
- 建立文件句柄
文件路径
文件路径有两种表示方法:绝对路径和相对路径
- 绝对路径是从磁盘根目录开始查找文件的完整路径。例如:
C:\aaa\c\电话.txt。 - 相对路径则是相对于当前程序所在目录的位置。在相对路径中,
.表示当前目录,..表示上一级目录。
例如,假设在 aaa 文件夹中有两个子文件夹 b 和 c,而运行的 Python 文件 x.py 位于 b 文件夹中,目标文件 电话.txt 在 c 文件夹中。这时,我们可以这样表示目标文件的相对路径:
'..\c\电话.txt'因为当前的工作目录是 aaa\b,而目标文件位于 aaa\c,所以我们需要用 .. 返回到父目录 aaa,然后再进入 c 文件夹找到目标文件
如果涉及到跨平台协作或程序移植,推荐使用相对路径。这样可以避免因环境变化而导致路径失效的问题
此外,我们还可以通过 Python 的 os 模块来获取当前工作路径:
import os
print(os.getcwd())在路径中,\ 用于分隔不同层级的目录。然而,由于 \ 连接某些字符可能具有特殊含义(如 \n 表示换行,\t 表示制表符等),因此需要注意对路径进行转义处理。常见的转义方法有两种:
- 使用双反斜杠
\\来表示单个反斜杠,例如:'C:\\aaa\\c\\电话.txt'。 - 在字符串前添加
r,使其成为“原始字符串”,从而避免转义问题,例如:r'C:\aaa\c\电话.txt'。
编码方式
文件的存储格式通常为 utf-8。需要注意的是,不同的操作系统默认使用的编码方式有所不同:
- Windows 操作系统默认使用
gbk编码 - Linux 和 macOS 则默认使用
utf-8编码
在实际开发中,为了避免因编码不一致导致的乱码问题,建议统一使用 utf-8 编码
创建文件句柄
确定好文件路径、操作模式和编码方式后,我们就可以创建一个文件句柄了。以下是创建文件句柄的代码示例:
f = open('电话.txt', mode='r', encoding='utf-8')上述代码的作用是:创建一个名为 f 的文件句柄,指向与当前工作路径相同的文件 电话.txt,并以只读模式打开该文件,同时指定其编码方式为 utf-8
文件的打开操作实际上是通过 Python 向操作系统发送指令来实现的
文件的读取
有了文件句柄后,我们就可以对文件进行各种操作。需要注意的是,直接打印文件句柄并不会显示文件内容,而是会输出文件对象的信息:
print(f) # <_io.TextIOWrapper name='电话.txt' mode='r' encoding='utf-8'>要读取文件内容,可以使用 .read() 方法:
print(f.read()).read() 方法会从光标当前位置开始读取文件内容,直到文件末尾,并将光标移动到文件末尾。如果此时再次调用 .read() 方法,则不会返回任何内容,因为光标已经到达文件末尾。
.read() 方法还支持传入参数,用于控制读取的字符数。例如:
print(f.read(3)) # 读取前三个字符需要注意的是,每一行文字末尾的换行符 \n 也会被算作一个字符。
除了 .read() 方法外,还可以使用 .readline() 方法逐行读取文件内容:
print(f.readline()) # 读取一行内容或者使用 .readlines() 方法将文件中的每一行内容存储为列表:
print(f.readlines()) # 输出类似 ['第一行\n', '第二行\n']此外,文件句柄本身是一个可迭代对象,可以直接通过循环逐行读取文件内容:
for line in f:
print(line)文件的写入
文件的写入操作主要通过 .write() 方法实现,且写入的内容必须为字符串类型。需要注意的是,只有在文件以可写模式(如 w 或 a)打开时,才能进行写入操作:
f = open('test', 'w', encoding='utf-8')
f.write('\n今天')
f.write('\n明天')
f.write('\n后天')光标操作
光标用于标识文件操作的起始位置。一般情况下,光标的初始位置在文件头部,随着读写操作的进行,光标会自动移动到相应位置。
如果我们希望手动调整光标位置,可以使用 .seek() 方法。例如:
f.seek(0, 0) # 将光标移动到文件头部
f.seek(0, 1) # 将光标移动到当前位置
f.seek(0, 2) # 将光标移动到文件末尾除了上述三种常见操作外,还可以通过 .seek() 方法自定义光标位置。例如:
f.seek(3) # 将光标移动到从文件开头开始的第 3 个字节处需要注意的是,这里的“字节”与编码方式密切相关。例如,在 gbk 编码中,每个中文字符占用 2 个字节;而在 utf-8 编码中,每个中文字符占用 3 个字节。
我们可以通过 .tell() 方法查看光标的当前位置。该方法返回从文件头到当前光标位置的字节数:
f.tell()文件的保存和关闭
在 Windows 系统中,文件内容通常会自动保存。但在 Linux 系统中,只有当内存中的数据达到一定阈值时,才会触发保存操作。为了确保数据安全,我们可以使用 .flush() 方法手动将内存中的内容刷新到硬盘:
f.flush()在完成文件操作后,应使用 .close() 方法关闭文件,将数据存储到硬盘并释放内存空间:
f.close()with 方法创建文件句柄
使用赋值方式创建文件句柄时,需要显式调用 .close() 方法关闭文件。这不仅增加了操作步骤,还容易因忘记关闭文件而导致资源泄漏
相比之下,使用 with 语句可以更优雅地管理文件操作。在 with 子句结束后,文件会自动关闭,无需手动调用 .close() 方法:
with open('test', 'w', encoding='utf-8') as f:
f.write('123')此外,with 语句还支持同时创建多个文件句柄:
f = open('test1', 'a', encoding='gbk')
f.write("嘿嘿")
f.close()
with open('test1', 'r', encoding='gbk') as f, open('test', 'r', encoding='utf-8')as f1:
print(f.read())
print(f1.read())文件操作模式细节
r 是只读模式,用于读取文件内容,不会对原文件进行任何修改
rb 模式用于读取字节流数据,常用于爬虫等场景
w 模式是清空写,当文件存在时会清空文件,文件不存在时创建文件:
- 打开文件时自动清空文件内容
- 写入内容,可以多次写入,每次写入都是在末尾追加
- 只有打开文件时会清空文件内容
- 通过移动光标,可以修改写入位置,如果该位置有内容,会造成覆盖
wb 模式是清空写字节,也是在爬虫中有所应用。
a 模式是追加写,当文件存在时会清空文件,文件不存在时创建文件。不管光标在哪里,都只会在最后追加内容:
f = open('test', 'a', encoding='utf-8')
f.write('啦啦啦')r+ 是读写模式,可读可写,原文件不会被清空,但是光标的初始位置会在文件的头部,如果不移动光标的话,新加入的内容会覆盖掉原来的文件内容:
f = open('test', 'r+', encoding='utf-8')
a = f.read()
print(a)
f.write('这是读写')w+ 是清空写读模式,打开文件时还是会将文件清空。后续的操作不会重新清空文件:
f = open('test', 'w+', encoding='utf-8')
f.write('哈哈哈')
f.seek(0,0) # 移动光标 移动到文件的头部
print(f.read())这里有个细节,因为写入完成后,光标的位置在文件的最后,需要将光标移动到文件头,再使用 .read() 方法才能读取到写入的文件内容。
a+ 是追加写读模式,所有内容无论光标在哪里,都只会添加到文件的末尾:
f = open('test', 'a+', encoding='utf-8')
f.write('嘿嘿')
f.seek(0,0) # 移动光标 移动到文件的头部
print(f.read())最常使用的文件操作模式有:r、w、a、a+(没文件时)和 r+(覆盖一些内容)
- 首选 with open(path, mode, encoding=...) as f —— 自动 close、异常安全。
- 文本/二进制是两套接口:r/w/a + encoding 处理文本,rb/wb/ab 处理 bytes。
- w 会清空文件,a 永远追加;想读又想写最常用 a+,定位光标用 seek。
- 大文件按行迭代 for line in f,避免 read() 一次性载入内存。
- 跨平台代码显式写 encoding='utf-8',路径推荐 pathlib.Path 而不是手拼字符串。
版权所有
版权归属:Shuo Liu
