Python文本文件/二进制文件读写教程:基础到实战全解析

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()
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容