Python文件读写是数据处理、程序开发的核心基础技能,分为文本文件(如.txt、.csv)和二进制文件(如.png、.mp3、.pkl)两大类——文本文件存储可读字符,二进制文件存储字节流(需解码才能识别)。本文从文件打开模式、基础读写到进阶技巧,搭配可直接运行的代码示例,覆盖搜索引擎高频检索需求(如Python读取大文件、文本文件编码设置、二进制文件读写),适合零基础快速掌握文件操作核心用法。
一、文件读写核心认知
1. 文本文件 vs 二进制文件
先明确两类文件的本质区别,避免“用错读写模式”导致文件损坏或乱码:
| 文件类型 | 存储形式 | 典型格式 | 读写关键 |
|---|---|---|---|
| 文本文件 | 字符编码(如UTF-8、GBK)的可读文本 | .txt、.csv、.py、.json | 需指定编码,按字符/行读写 |
| 二进制文件 | 原始字节流(无固定编码) | .png、.mp3、.pkl、.exe | 无需编码,按字节/缓冲区读写 |
2. 核心打开模式(必记)
Python通过open()函数打开文件,模式参数决定读写方式,核心模式如下:
| 模式 | 含义 | 适用文件类型 |
|---|---|---|
r |
只读(默认模式),文件不存在则报错 | 文本/二进制文件 |
w |
只写,文件不存在则创建,存在则覆盖内容 | 文本/二进制文件 |
a |
追加,文件不存在则创建,内容写在末尾 | 文本/二进制文件 |
r+ |
读写,文件不存在则报错 | 文本/二进制文件 |
w+ |
读写,文件不存在则创建,存在则覆盖 | 文本/二进制文件 |
a+ |
读写,文件不存在则创建,内容追加在末尾 | 文本/二进制文件 |
t |
文本模式(默认,可省略),需指定编码 | 仅文本文件(如rt=默认文本只读) |
b |
二进制模式,无需编码 | 仅二进制文件(如rb=二进制只读) |
关键:文本文件读写需显式指定
encoding(如encoding='utf-8'),二进制文件必须加b模式(如rb/wb)且不能指定编码。
3. 文件读写的核心流程
无论哪种文件,读写都遵循“打开→操作→关闭”三步,但Python推荐用with语句(自动关闭文件,避免内存泄漏):
# 通用流程(with语句自动管理文件句柄)
with open("文件路径", "模式", encoding="编码") as f:
# 读/写操作(如f.read()、f.write())
二、文本文件读写(重点:编码与行操作)
文本文件是最常用的文件类型,核心关注编码设置(避免乱码)和行读写(高效处理大文件)。
1. 基础读写:读取整个文件/写入内容
# 示例1:读取整个文本文件(适合小文件)
with open("test.txt", "r", encoding="utf-8") as f:
content = f.read() # 读取所有内容为字符串
print("文件内容:\n", content)
# 示例2:写入文本内容(覆盖原有内容)
with open("test.txt", "w", encoding="utf-8") as f:
f.write("Python文本文件写入测试\n") # 写入字符串,需手动加换行符\n
f.write("第二行内容:编码为UTF-8")
# 示例3:追加内容到文件末尾
with open("test.txt", "a", encoding="utf-8") as f:
f.write("\n追加的第三行内容")
2. 高效读写:按行读取(适合大文件)
读取超大文本文件(如几GB的日志)时,read()会一次性加载所有内容到内存,导致内存溢出,推荐按行读取:
# 示例4:按行读取(方法1:for循环遍历,最简洁)
with open("large_file.txt", "r", encoding="utf-8") as f:
for line in f: # 逐行读取,每行包含末尾的\n
print("当前行:", line.strip()) # strip()去除换行符和空格
# 示例5:按行读取(方法2:readline()读取单行)
with open("test.txt", "r", encoding="utf-8") as f:
line1 = f.readline() # 读取第一行
line2 = f.readline() # 读取第二行
print("第一行:", line1.strip())
print("第二行:", line2.strip())
# 示例6:按行读取(方法3:readlines()读取所有行到列表)
with open("test.txt", "r", encoding="utf-8") as f:
lines = f.readlines() # 所有行组成列表,每行含\n
print("所有行:", [line.strip() for line in lines])
3. 进阶技巧:读写时处理编码与异常
(1)解决中文乱码问题
中文乱码的核心是“编码不匹配”(文件实际编码与encoding参数不一致),常见解决方案:
# 示例7:指定正确编码(UTF-8/GBK)
try:
# 尝试UTF-8编码读取
with open("中文文件.txt", "r", encoding="utf-8") as f:
print(f.read())
except UnicodeDecodeError:
# UTF-8失败,尝试GBK编码(Windows系统常见)
with open("中文文件.txt", "r", encoding="gbk") as f:
print(f.read())
(2)读写时添加异常捕获(避免程序崩溃)
# 示例8:文件读写异常处理(文件不存在、权限不足等)
try:
with open("test.txt", "r", encoding="utf-8") as f:
content = f.read()
except FileNotFoundError:
print("错误:文件不存在!")
except PermissionError:
print("错误:没有文件读写权限!")
except UnicodeDecodeError:
print("错误:编码不匹配,无法读取!")
else:
print("读取成功:", content)
三、二进制文件读写(重点:字节流操作)
二进制文件(如图片、音频、压缩包)需用rb/wb/ab模式,读写单位是字节(而非字符),核心是处理bytes类型数据。
1. 基础读写:复制二进制文件(如图片/音频)
# 示例9:复制图片文件(二进制读写核心场景)
# 读取原图片(二进制只读)
with open("source.png", "rb") as f_in:
byte_data = f_in.read() # 读取所有字节(bytes类型)
print("读取的字节数:", len(byte_data))
# 写入新图片(二进制只写)
with open("copy.png", "wb") as f_out:
f_out.write(byte_data) # 写入字节流
print("图片复制完成!")
2. 高效读写:分块读取大二进制文件
处理超大二进制文件(如几GB的视频)时,分块读取可避免内存溢出:
# 示例10:分块复制大文件(如视频/压缩包)
chunk_size = 1024 * 1024 # 每次读取1MB(可调整)
with open("large_video.mp4", "rb") as f_in:
with open("video_copy.mp4", "wb") as f_out:
while True:
chunk = f_in.read(chunk_size) # 分块读取字节
if not chunk: # 读取到末尾(chunk为空)
break
f_out.write(chunk) # 分块写入
print("大文件复制完成!")
3. 进阶:二进制文件与Python对象互转
二进制文件常用来存储序列化后的Python对象(如pickle序列化,见前文),本质是字节流的读写:
import pickle
# 示例11:二进制文件存储Python对象(pickle序列化)
data = {"name": "张三", "age": 25, "scores": [90, 85]}
# 序列化对象为字节流
byte_data = pickle.dumps(data)
# 写入二进制文件
with open("data.pkl", "wb") as f:
f.write(byte_data)
# 从二进制文件读取并反序列化
with open("data.pkl", "rb") as f:
restored_data = pickle.load(f)
print("恢复的对象:", restored_data)
四、文件读写的核心优化技巧
1. 定位文件指针(随机读写)
文件读写时,指针指向当前操作位置,可通过seek()调整指针位置,实现随机读写:
# 示例12:文件指针操作(文本文件)
with open("test.txt", "r+", encoding="utf-8") as f:
# 读取前5个字符
content1 = f.read(5)
print("前5个字符:", content1)
print("当前指针位置:", f.tell()) # 输出5(字符数,文本模式)
# 指针移到文件开头(offset=0,whence=0表示从开头算起)
f.seek(0, 0)
content2 = f.readline()
print("从头读取第一行:", content2.strip())
# 示例13:二进制文件指针(按字节定位)
with open("source.png", "rb") as f:
f.seek(100, 0) # 从开头移到第100字节
chunk = f.read(50) # 读取100-149字节
print("读取的字节:", chunk)
seek()参数说明:
-
offset:偏移量(文本模式按字符,二进制模式按字节); -
whence:基准位置(0=文件开头,1=当前位置,2=文件末尾)。
2. 批量处理多个文件(结合os模块)
import os
# 示例14:批量读取指定目录下所有.txt文件
dir_path = "text_files"
for filename in os.listdir(dir_path):
if filename.endswith(".txt"):
file_path = os.path.join(dir_path, filename)
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
print(f"=== {filename} 内容 ===")
print(content[:100]) # 输出前100字符
3. 提高读写效率:缓冲区设置
open()函数的buffering参数控制缓冲区大小,默认自动缓冲,调整后可优化大文件读写速度:
# 示例15:设置缓冲区大小(二进制文件)
# buffering=1024*1024:1MB缓冲区(适合大文件)
with open("large_file.bin", "rb", buffering=1024*1024) as f:
data = f.read()
五、完整实战案例
场景1:文本文件数据统计(统计单词出现次数)
# 统计文本文件中每个单词出现的次数
with open("article.txt", "r", encoding="utf-8") as f:
content = f.read().lower() # 转为小写,统一统计
# 简单处理:去除标点,分割单词
import string
# 去除文本中的标点符号
for char in string.punctuation:
content = content.replace(char, " ")
# 分割为单词列表
words = content.split()
# 统计单词频率
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
# 输出出现次数前10的单词
sorted_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True)
print("单词出现次数Top10:")
for word, count in sorted_words[:10]:
print(f"{word}: {count}次")
场景2:二进制文件拆分与合并(大文件分割)
import os
# 1. 拆分大文件(按10MB拆分)
def split_file(file_path, chunk_size=10*1024*1024):
# 创建拆分后的文件存储目录
dir_name = "split_chunks"
if not os.path.exists(dir_name):
os.makedirs(dir_name)
with open(file_path, "rb") as f_in:
chunk_idx = 0
while True:
chunk = f_in.read(chunk_size)
if not chunk:
break
# 拆分后的文件名
chunk_file = os.path.join(dir_name, f"chunk_{chunk_idx}.bin")
with open(chunk_file, "wb") as f_out:
f_out.write(chunk)
print(f"生成拆分文件:{chunk_file}")
chunk_idx += 1
# 2. 合并拆分文件
def merge_file(chunk_dir, output_file):
with open(output_file, "wb") as f_out:
# 按顺序读取拆分文件
for filename in sorted(os.listdir(chunk_dir)):
if filename.startswith("chunk_"):
chunk_path = os.path.join(chunk_dir, filename)
with open(chunk_path, "rb") as f_in:
f_out.write(f_in.read())
print(f"文件合并完成:{output_file}")
# 执行拆分与合并
split_file("large_file.iso") # 拆分大文件
merge_file("split_chunks", "merged_file.iso") # 合并文件
六、常见问题与避坑指南
| 常见错误 | 原因分析 | 解决方法 |
|---|---|---|
| 文本文件读取乱码 | 编码不匹配(如文件是GBK,用UTF-8读取) | 尝试encoding='utf-8'/'gbk'/'gb2312' |
| 二进制文件读写报错 | 未加b模式(如用r代替rb),或指定了encoding参数 |
改用rb/wb模式,删除encoding参数 |
| 大文件读取内存溢出 | 用read()一次性加载所有内容 |
按行(文本)或分块(二进制)读取 |
| 文件找不到报错 | 文件路径错误(相对路径/绝对路径混淆),或文件被删除 | 检查文件路径,用os.path.exists()验证 |
| 权限错误(PermissionError) | 无文件读写权限,或文件被其他程序占用 | 关闭占用程序,提升权限或修改文件权限 |
| 写入后文件为空 | 忘记关闭文件(未用with语句),缓冲区未刷新 | 用with语句自动关闭,或手动调用f.flush()
|