Python文件操作全解析:打开、关闭与读写实战
在Python开发中,文件操作是高频需求——无论是读取配置文件、处理日志、还是读写数据,都离不开文件的打开、读写与关闭。但很多初学者容易在“打开模式”“资源释放”“路径处理”等环节踩坑,导致文件损坏、数据丢失或代码报错。本文将从基础操作→模式详解→读写方法→CSV处理→路径管理,全方位讲解Python文件操作的核心知识点,帮你写出安全、高效的文件处理代码。
一、文件操作的基本流程:打开→操作→关闭
文件操作的核心步骤可概括为:
- 打开文件:用
open()函数建立与文件的连接,返回文件对象; - 操作文件:通过文件对象的方法(如
read()、write())读写内容; - 关闭文件:释放文件资源(必须执行,否则可能导致数据未写入或资源占用)。
1. 基础打开与关闭:open()与close()
# 步骤1:打开文件(r模式:只读,需文件存在)
# 参数:文件名、打开模式、编码(文本文件必指定,避免乱码)
f = open("test.txt", "r", encoding="utf-8")# 步骤2:操作文件(读取内容)
content = f.read()
print("文件内容:", content)# 步骤3:关闭文件(释放资源)
f.close()
注意:若忘记调用close(),可能导致:
- 文件被锁定,其他程序无法修改;
- 缓存数据未写入磁盘(尤其写操作),导致内容丢失;
- 资源泄露(打开文件数量有限制)。
2. 更安全的方式:with语句自动关闭
with语句会在代码块执行完毕后自动关闭文件,无需手动调用close(),是推荐的最佳实践。
# with语句:自动管理文件关闭
with open("test.txt", "r", encoding="utf-8") as f: # 冒号后缩进为操作块content = f.read()print("文件内容:", content)# 代码块结束后,文件已自动关闭,无需手动close()
# 此时再操作f会报错(文件已关闭)
# print(f.read()) # 报错:ValueError: I/O operation on closed file.
优势:即使操作中发生异常,with也能保证文件正确关闭,安全性远高于手动close()。
二、文件打开模式:选择正确的操作方式
open()函数的第二个参数是“打开模式”,决定文件的操作权限(读/写/追加)和数据类型(文本/二进制)。常用模式如下:
1. 文本模式(默认,处理字符串)
| 模式 | 含义 | 特点 |
|---|---|---|
r | 只读(默认) | 文件必须存在,否则报错;指针在文件开头 |
w | 只写(覆盖) | 文件不存在则创建;存在则清空原内容;指针在开头 |
a | 只写(追加) | 文件不存在则创建;存在则在末尾追加;指针在末尾 |
r+ | 读写 | 文件必须存在;可读写,指针在开头 |
w+ | 读写(覆盖) | 文件不存在则创建;存在则清空;可读写 |
a+ | 读写(追加) | 文件不存在则创建;写操作只能追加;读操作需移动指针 |
示例:不同写模式的区别
# 1. w模式:覆盖写(每次运行清空原内容)
with open("test.txt", "w", encoding="utf-8") as f:f.write("第一次写入\n") # 文件内容:第一次写入# 再次用w模式写入,覆盖原内容
with open("test.txt", "w", encoding="utf-8") as f:f.write("第二次写入\n") # 文件内容:第二次写入# 2. a模式:追加写(在末尾添加)
with open("test.txt", "a", encoding="utf-8") as f:f.write("追加的内容\n") # 文件内容:第二次写入\n追加的内容# 3. r+模式:读写(需文件存在,可在任意位置写)
with open("test.txt", "r+", encoding="utf-8") as f:f.seek(3) # 移动指针到第3个字符后(0-based)f.write("插入") # 从指针位置开始覆盖写入# 最终内容:第二插入写入\n追加的内容(原"次"被"插入"覆盖)
2. 二进制模式(处理非文本文件,如图片/视频)
二进制模式用于处理字节流(非文本文件),模式名后加b(如rb、wb),无需指定encoding(二进制操作不涉及编码)。
| 模式 | 含义 | 用途 |
|---|---|---|
rb | 二进制读 | 读取图片、视频、压缩包等 |
wb | 二进制写 | 写入图片、视频等(覆盖原文件) |
ab | 二进制追加 | 向二进制文件末尾追加内容 |
示例:复制图片(二进制操作)
# 二进制读模式打开原图
with open("source.jpg", "rb") as src:# 二进制写模式创建新图(复制内容)with open("copy.jpg", "wb") as dst:dst.write(src.read()) # 读取字节流并写入新文件print("图片复制完成")
三、文本文件读写方法:按需求选择
文件对象提供了多种读写方法,需根据场景(如文件大小、读取方式)选择。
1. 读取方法:read() / readline() / readlines()
| 方法 | 功能 | 适用场景 |
|---|---|---|
read(size) | 读取指定字节数(size为None时读全部) | 小文件一次性读取 |
readline() | 读取一行(包括换行符\n) | 大文件按行读取(节省内存) |
readlines() | 读取所有行,返回列表(每行一个元素) | 中等大小文件,需按行处理 |
示例:读取大文件(按行读取更高效)
# 大文件(如10GB日志)不适合read()(占满内存),用readline()逐行处理
with open("large_log.txt", "r", encoding="utf-8") as f:while True:line = f.readline() # 逐行读取if not line: # 读到末尾(空字符串)break# 处理当前行(如过滤包含"error"的日志)if "error" in line.lower():print("错误日志:", line.strip())
2. 写入方法:write() / writelines()
| 方法 | 功能 | 注意 |
|---|---|---|
write(s) | 写入字符串s | 不会自动换行,需手动加\n |
writelines(seq) | 写入字符串序列(如列表) | 不会自动换行,需手动加\n |
示例:写入内容
# 1. write():写入单字符串
with open("output.txt", "w", encoding="utf-8") as f:f.write("第一行内容\n") # 手动加换行符f.write("第二行内容\n")# 2. writelines():写入列表
lines = ["第三行\n", "第四行\n", "第五行\n"]
with open("output.txt", "a", encoding="utf-8") as f:f.writelines(lines) # 列表元素需自带换行符
四、CSV文件处理:用标准库csv
CSV(逗号分隔值)是常用数据交换格式,Python标准库csv提供了便捷的读写工具(比手动分割字符串更可靠)。
1. 读取CSV文件(csv.reader)
import csv# 读取CSV文件(默认逗号分隔)
with open("data.csv", "r", encoding="utf-8") as f:reader = csv.reader(f) # 创建reader对象header = next(reader) # 读取表头(第一行)print("表头:", header)# 遍历数据行for row in reader:print("数据行:", row) # row是列表,每个元素为一列值
示例CSV内容(data.csv):
姓名,年龄,城市
张三,25,北京
李四,22,上海
输出:
表头: ['姓名', '年龄', '城市']
数据行: ['张三', '25', '北京']
数据行: ['李四', '22', '上海']
2. 写入CSV文件(csv.writer)
import csv# 写入CSV文件
data = [["姓名", "年龄", "城市"], # 表头["王五", 30, "广州"],["赵六", 28, "深圳"]
]with open("new_data.csv", "w", encoding="utf-8", newline="") as f:# newline="":避免Windows下自动添加空行writer = csv.writer(f) # 创建writer对象writer.writerows(data) # 写入多行(可传入列表)print("CSV写入完成")
注意:Windows系统下写CSV需指定newline="",否则每行之间会多一个空行。
五、路径处理:用os.path模块跨平台兼容
手动拼接路径(如"data/file.txt")在不同系统(Windows用\,Linux/Mac用/)会出错,推荐用os.path模块处理路径。
1. 常用路径函数
| 函数 | 功能 | 示例 |
|---|---|---|
os.path.join(path1, path2, ...) | 拼接路径(自动适配系统分隔符) | os.path.join("data", "logs", "test.txt") → data/logs/test.txt(Linux)或data\logs\test.txt(Windows) |
os.path.exists(path) | 判断路径是否存在 | os.path.exists("data") → True/False |
os.path.isfile(path) | 判断是否为文件 | os.path.isfile("test.txt") → True/False |
os.path.isdir(path) | 判断是否为目录 | os.path.isdir("data") → True/False |
os.makedirs(path, exist_ok=False) | 递归创建目录 | os.makedirs("data/logs") → 创建多层目录 |
2. 实战:安全创建目录并写入文件
import os# 目标文件路径:./data/reports/2023.txt
dir_path = os.path.join(".", "data", "reports") # 目录路径
file_path = os.path.join(dir_path, "2023.txt") # 文件路径# 步骤1:如果目录不存在,创建(exist_ok=True:目录存在不报错)
if not os.path.exists(dir_path):os.makedirs(dir_path, exist_ok=True)print(f"创建目录:{dir_path}")# 步骤2:写入文件
with open(file_path, "w", encoding="utf-8") as f:f.write("2023年报告内容")print(f"文件已写入:{file_path}")
六、避坑指南:文件操作常见错误及解决
1. 编码错误(UnicodeDecodeError)
问题:读取文件时未指定正确编码(如文件是gbk编码,却用utf-8读取)。
解决:指定正确编码,或尝试encoding="utf-8-sig"(处理带BOM的UTF-8文件):
with open("test.txt", "r", encoding="gbk") as f: # 用文件实际编码pass
2. 文件不存在(FileNotFoundError)
问题:r模式打开不存在的文件。
解决:检查路径是否正确,或先用os.path.exists()判断:
import os # 导入os模块
file_path = "test.txt"
if not os.path.exists(file_path):print(f"文件不存在:{file_path}")
else:with open(file_path, "r") as f:pass
3. 权限错误(PermissionError)
问题:无权限读写文件(如尝试写入只读目录)。
解决:检查文件/目录权限,或更换路径(如用户目录)。
4. 忘记关闭文件导致数据丢失
问题:用open()打开文件后未close(),且程序意外退出,导致缓存数据未写入。
解决:强制使用with语句,自动管理关闭和缓存刷新。
七、总结:文件操作最佳实践
- 优先用
with语句:自动关闭文件,避免资源泄露; - 明确指定编码:文本文件必加
encoding="utf-8"(或实际编码),避免乱码; - 按文件大小选读写方式:大文件用
readline()逐行处理,小文件用read()一次性读取; - 用
os.path处理路径:跨平台兼容,避免手动拼接; - 二进制文件不加编码:
rb/wb模式操作非文本文件,无需指定encoding; - CSV用
csv库:比手动分割字符串更可靠(处理逗号包含在字段中的情况)。
掌握这些知识点,就能应对90%以上的文件操作场景。文件操作看似简单,但细节决定成败——一次编码错误或未关闭的文件,都可能导致程序崩溃或数据丢失,务必谨慎处理。
