Python 文件操作全解析:模式、方法与实战案例
在 Python 开发中,文件操作是基础且核心的技能之一,无论是数据存储、日志记录还是配置读取,都离不开对文件的读写操作。本文将结合实战代码,详细讲解 Python 文件操作的模式分类、常用方法,并通过完整案例演示如何高效实现文件的创建、写入、读取与读写结合操作,帮助初学者快速掌握文件操作精髓。
一、文件操作核心概念
在开始代码实战前,我们先明确文件操作的两个核心维度:打开模式和常用方法,这是后续所有操作的基础。
1.1 文件打开模式分类
Python 中通过 open()
函数打开文件时,需指定 mode
参数(操作模式),不同模式对应不同的文件操作权限。根据功能可分为写模式、读模式、读写模式和二进制模式四大类,具体如下表所示:
模式分类 | 模式符号 | 功能说明 | 适用场景 |
---|---|---|---|
写模式 | w | 只写权限,文件不存在则创建,存在则覆盖原有内容 | 全新文件创建、内容重写(如生成报告) |
a | 追加写权限,文件不存在则创建,存在则在末尾追加内容 | 日志记录、数据增量写入 | |
读模式 | r | 只读权限,文件必须存在,否则报错 | 配置文件读取、数据解析 |
读写模式 | w+ | 读写权限,文件不存在则创建,存在则清空内容 | 需同时读写且允许覆盖的场景 |
a+ | 追加读写权限,文件不存在则创建,写操作默认追加到末尾 | 需读写且保留历史内容的场景(如日志查询 + 新增) | |
r+ | 读写权限,文件必须存在,写操作替换同等字节内容 | 对已有文件内容修改(如修改配置项) | |
二进制模式 | wb /ab /rb | 在对应模式后加 b ,以二进制形式操作(非文本文件) | 图片、音频、视频等非文本文件处理 |
wb+ /ab+ /rb+ | 二进制读写模式 | 二进制文件的读写结合操作 |
1.2 文件操作常用方法
打开文件后,通过文件对象(如 f
)调用方法实现具体操作,常用方法及功能如下表:
方法名 | 功能说明 | 示例 |
---|---|---|
write(str) | 写入字符串内容,换行需手动加 \n | f.write("你好\n") |
writelines(list) | 一次性写入多行内容(接收字符串列表) | f.writelines(["111\n", "222\n"]) |
tell() | 返回当前文件指针到文件头的字节数(定位指针位置) | print(f.tell()) |
print(data, file=f) | 将数据打印到文件(等同于写入,支持多种数据类型) | print([1,2,3], file=f) |
read() | 一次性读取文件所有内容(返回字符串) | content = f.read() |
read(n) | 读取指定数量的字符(n 为字符数) | content = f.read(10) (读 10 个字符) |
readline() | 一次读取一行内容(包含换行符 \n ) | line = f.readline() |
readlines() | 读取所有行,返回字符串列表(每行是一个元素) | lines = f.readlines() |
seek(offset) | 移动文件指针到指定位置(offset=0 表示文件头) | f.seek(0) (指针回到开头) |
二、实战案例:文件操作完整流程
下面结合具体代码,分场景演示文件的创建与写入、读取、读写结合和迭代器遍历操作,所有案例均经过实测可直接运行。
2.1 案例 1:文件创建与写入(3 种实现方式)
文件写入是最基础的操作,常用 w
(覆盖写)和 a
(追加写)模式,推荐使用 with
语句(自动关闭文件,避免资源泄漏),也可手动调用 close()
关闭文件。
方式 1:with + w 模式
(覆盖写,自动关闭)
# 路径说明:r'.\data\date3.txt' 表示当前目录下的 data 文件夹中的 date3.txt
# 若 data 文件夹不存在,会报错,需先手动创建或通过代码创建
with open(r'.\data\date3.txt', mode='w', encoding='utf-8') as f:# 1. 单字符串写入(换行用 \n)f.write('你好\n')f.write('hello\n')# 2. 多行写入(接收字符串列表,需手动加 \n)f.writelines(['111\n', '222\n', '333\n', '444\n'])# 3. 查看当前指针位置(字节数)print("当前指针位置(字节):", f.tell()) # 输出取决于写入内容的字节数(utf-8中中文占3字节)# 4. 使用 print 写入(支持非字符串类型,自动转换为字符串)print('hello', file=f) # 等同于 f.write('hello\n')(print 自动加换行)print('教育', file=f)print([1, 2, 3], file=f) # 列表会被转为字符串 "[1, 2, 3]" 写入
方式 2:手动 open + a 模式
(追加写,手动关闭)
若需多次向同一文件追加内容(如日志),可使用 a
模式,注意手动打开后必须调用 close()
关闭文件:
# 打开文件(a 模式:追加写)
f = open(r'.\a\data.txt', mode='a', encoding='utf-8')
try:f.write('你好\n')f.write('hello\n')f.writelines(['111\n', '2222\n', '333\n', '666\n'])print("当前指针位置:", f.tell())print('helloworld', file=f)print('教育', file=f)print([1, 2, 3], file=f)
finally:# 手动关闭文件(避免资源泄漏)f.close()
方式 3:with + a 模式
(追加写,自动关闭)
推荐使用 with
语句实现追加写,无需手动关闭:
with open(r'.\data\date4.txt', mode='a', encoding='utf-8') as f:f.write('你好\n')f.write('hello\n')f.write('你好\n')f.writelines(['111\n', '222\n', '333\n', '444\n'])print("当前指针位置:", f.tell())
2.2 案例 2:文件读取(5 种常用方式)
文件读取需使用 r
模式(只读),需确保文件已存在,否则会抛出 FileNotFoundError
。以下演示 5 种读取方式,覆盖不同场景需求。
# 使用 with 语句读取文件(自动关闭)
with open(r'.\data\date3.txt', mode='r', encoding='utf-8') as f:# 1. 读取所有内容(一次性读入内存,大文件不推荐)print("=== 读取所有内容 ===")all_content = f.read()print(all_content)# 注意:read() 后指针会移到文件末尾,后续读取需先移动指针f.seek(0) # 指针移回文件头# 2. 读取指定字符数(n=10,读取前10个字符)print("\n=== 读取前10个字符 ===")part_content = f.read(10)print(part_content)# 3. 读取一行内容(包含换行符 \n)print("\n=== 读取一行内容 ===")line1 = f.readline()print(line1)# 4. 读取所有行(返回列表,每行是一个元素)print("\n=== 读取所有行(列表形式) ===")f.seek(0) # 指针移回开头all_lines = f.readlines()print(all_lines)# 5. 读取指定字节内的行数(n=10,读取10字节内的所有完整行)print("\n=== 读取10字节内的行数 ===")f.seek(0)lines_limit = f.readlines(10)print(lines_limit)
关键注意点:
- 读取操作会移动文件指针,
read()
/readline()
后指针会指向当前读取位置,再次读取需用f.seek(0)
移回文件头。 - 大文件(如几 GB 日志)不推荐使用
read()
或readlines()
(一次性读入内存),建议用for
循环逐行读取(见 2.4 节)。
2.3 案例 3:文件读写结合(r+ 模式实战)
r+
模式支持同时读写文件,且文件必须存在,写操作会替换同等字节的内容(而非追加),适合对已有文件内容进行修改。
# r+ 模式:读写结合(文件必须存在)
with open(r'.\data\date3.txt', mode='r+', encoding='utf-8') as f:# 1. 先写入内容(替换开头同等字节)f.write('hello123456789') # 原文件开头内容会被替换为该字符串# 2. 指针移回文件头(否则读取不到刚写入的内容)f.seek(0)# 3. 读取修改后的文件内容modified_content = f.read()print("修改后的文件内容:")print(modified_content)
效果说明:
若原文件开头是 你好
(utf-8 占 6 字节),写入 hello123
(9 字节)后,原 你好
会被完全替换,后续内容依次后移。
2.4 案例 4:迭代器遍历文件(高效读取大文件)
Python 文件对象本身是可迭代对象,通过 for
循环逐行读取文件,无需一次性加载所有内容,是处理大文件的最优方式。以下案例演示如何读取指定行(如第 2 行)。
# 迭代器遍历文件(逐行读取,高效处理大文件)
with open(r'.\data\date3.txt', mode='r', encoding='utf-8') as f:# enumerate(f):获取每行的索引(从0开始)和内容for index, line in enumerate(f):# 获取第2行(索引+1 == 2,因为索引从0开始)if index + 1 == 2:# line.strip():去除行首尾的空格和换行符print(f"第2行内容:{line.strip()}")break # 找到目标行后退出循环,避免多余操作
优势:
- 内存占用低:逐行读取,仅加载当前行内容,适合几 GB 甚至更大的文件。
- 代码简洁:无需手动处理指针,
for
循环自动迭代每行内容。
三、常见问题与解决方案
在文件操作中,初学者常遇到路径错误、编码错误等问题,以下是高频问题的解决方案:
3.1 路径错误(FileNotFoundError)
错误场景:open(r'.\data\date3.txt')
报错,提示文件不存在。
原因:.\data
文件夹不存在,或文件路径拼写错误。
解决方案:
- 手动创建
data
文件夹; - 用代码自动创建文件夹(需导入
os
模块):
import os
# 若 data 文件夹不存在则创建
if not os.path.exists(r'.\data'):os.makedirs(r'.\data')
# 再创建文件
with open(r'.\data\date3.txt', mode='w', encoding='utf-8') as f:f.write('你好')
3.2 编码错误(UnicodeDecodeError)
错误场景:读取文件时报错 UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 44: illegal multibyte sequence
。
原因:文件保存时的编码与读取时指定的 encoding
不一致(如文件是 utf-8
编码,读取时用了 gbk
)。
解决方案:
读取时明确指定文件实际编码(通常为 utf-8
或 gbk
):
with open(r'.\data\date3.txt', mode='r', encoding='utf-8') as f:# 若 utf-8 报错,尝试 encoding='gbk'print(f.read())
3.3 资源泄漏(文件未关闭)
错误场景:手动 open
文件后未调用 close()
,导致文件被占用(无法删除或修改)。
解决方案:
- 推荐使用
with
语句(自动关闭文件,即使发生异常); - 若手动
open
,需在finally
中调用close()
(见 2.1 节方式 2)。
四、总结
本文从文件操作的核心概念出发,详细讲解了模式分类和常用方法,并通过 4 个实战案例覆盖了文件的创建、写入、读取、读写结合和迭代器遍历操作。关键要点总结如下:
模式选择:
- 覆盖写用
w
,追加写用a
,只读用r
,读写结合根据需求选w+
/a+
/r+
; - 非文本文件(图片、音频)必须用二进制模式(加
b
)。
- 覆盖写用
方法使用:
- 写入用
write()
/writelines()
,读取用read()
/readline()
/readlines()
; - 指针操作
tell()
/seek()
是读写结合的关键。
- 写入用
最佳实践:
- 处理文本文件时指定
encoding='utf-8'
,避免编码错误; - 大文件用迭代器逐行读取,小文件可用
read()
一次性读取; - 始终用
with
语句打开文件,避免资源泄漏。
- 处理文本文件时指定