Python 文件操作教程:open () 函数、读写模式与文件关闭全解析

181 阅读8分钟

一、文件操作核心逻辑:先理解“打开-操作-关闭”

Python操作文件遵循固定流程:

  1. 打开文件:通过open()函数建立程序与文件的连接,返回“文件对象”(也称文件句柄);
  2. 操作文件:通过文件对象执行读、写、追加等操作;
  3. 关闭文件:通过close()方法释放文件资源(避免资源泄露、文件损坏)。

类比理解:操作文件就像操作水杯——打开文件=拿起水杯,读写=倒水/接水,关闭文件=放下水杯(不放下会占用手的资源)。

二、核心函数:open() 打开文件(必掌握)

open()是Python操作文件的入口函数,所有文件操作都从它开始,先掌握其语法和参数。

1. open() 基础语法

file_object = open(file, mode='r', encoding=None)

参数说明:

参数作用说明示例
file必选参数,文件路径(绝对路径/相对路径)'./test.txt''/usr/data/log.txt'
mode可选参数,文件打开模式(默认r,只读),决定能对文件执行的操作'r'(读)、'w'(写)、'a'(追加)
encoding可选参数,文件编码格式(文本文件必备,推荐utf-8encoding='utf-8'

路径说明:

  • 相对路径:以当前程序所在目录为基准,如'test.txt'(程序同目录)、'./data/test.txt'(程序目录下的data文件夹);
  • 绝对路径:文件在系统中的完整路径,如Windows:'C:\Users\admin\test.txt',Linux/Mac:'/home/admin/test.txt'(注意Windows路径需转义,或用r'C:\Users\admin\test.txt')。

2. 核心:文件打开模式(mode参数)

mode参数决定了文件的操作类型,新手最易混淆,以下是高频使用的模式及区别:

模式中文说明核心特性适用场景
r只读模式默认模式,文件必须存在,否则报错;只能读取文件内容,不能修改读取配置文件、日志文件
w只写模式文件不存在则创建,文件存在则清空原有内容;只能写入内容,不能读取新建文件、覆盖写入数据
a追加模式文件不存在则创建,文件存在则在末尾追加内容;只能写入,不能读取日志追加、数据补录
r+读写模式文件必须存在,可同时读取和写入(写入会覆盖原有内容)读取并修改文件(需谨慎)
w+写读模式文件不存在则创建,清空原有内容;可先写后读新建文件并验证写入内容
a+追加读模式文件不存在则创建,在末尾追加内容;可追加后读取追加数据后查看完整内容
b二进制模式与上述模式结合使用(如rbwb),用于操作二进制文件(图片、视频、压缩包)读取/写入二进制文件

关键提醒

  • 文本文件(.txt、.py、.conf)操作需指定encoding='utf-8',避免中文乱码;
  • 二进制文件(.jpg、.zip、.mp4)操作不能指定encoding,且模式需加b(如rb)。

三、文件读取操作:从文件中获取内容

读取文件是最常用的操作,核心方法有read()readline()readlines(),按需选择。

1. 一次性读取全部内容(read())

适合小文件(几十KB内),一次性读取所有内容到字符串。

# 示例:读取文本文件
# 步骤1:打开文件(只读模式,指定utf-8编码)
f = open('./test.txt', mode='r', encoding='utf-8')

# 步骤2:读取全部内容
content = f.read()
print("文件全部内容:")
print(content)

# 步骤3:关闭文件(必须执行)
f.close()

2. 逐行读取(readline())

适合大文件,每次读取一行,避免一次性加载过多内容占用内存。

# 示例:逐行读取文件
f = open('./test.txt', mode='r', encoding='utf-8')

# 循环读取每一行,直到读取完毕(readline()返回空字符串表示结束)
print("逐行读取内容:")
while True:
    line = f.readline()
    if not line:
        break
    # 去除每行末尾的换行符(\n)
    print(line.strip())

f.close()

3. 读取所有行到列表(readlines())

将文件每一行作为列表元素,方便遍历和索引。

# 示例:读取所有行到列表
f = open('./test.txt', mode='r', encoding='utf-8')

lines = f.readlines()
print("文件行列表:", lines)  # 每行末尾带\n,如['第一行\n', '第二行\n']

# 遍历列表处理每行内容
print("处理后内容:")
for index, line in enumerate(lines):
    print(f"第{index+1}行:{line.strip()}")

f.close()

4. 读取二进制文件(如图片)

# 示例:读取图片文件
f = open('./logo.jpg', mode='rb')  # 二进制只读模式,无需encoding
img_data = f.read()
print(f"图片字节数:{len(img_data)}")
f.close()

# 写入新图片(验证读取内容)
f_new = open('./logo_copy.jpg', mode='wb')
f_new.write(img_data)
f_new.close()

四、文件写入操作:向文件中保存内容

写入文件需注意模式选择(w覆盖、a追加),核心方法是write()writelines()

1. 覆盖写入(mode='w')

文件不存在则创建,存在则清空原有内容,写入新内容。

# 示例:覆盖写入文本
f = open('./write_test.txt', mode='w', encoding='utf-8')

# 写入字符串
f.write("Python文件写入测试\n")
f.write("第二行内容\n")

# 关闭文件(写入后必须关闭,否则内容可能未保存)
f.close()

# 验证写入结果
f_read = open('./write_test.txt', mode='r', encoding='utf-8')
print("覆盖写入后的内容:")
print(f_read.read())
f_read.close()

2. 追加写入(mode='a')

在文件末尾添加内容,不覆盖原有内容。

# 示例:追加写入文本
f = open('./write_test.txt', mode='a', encoding='utf-8')

f.write("追加的第三行内容\n")
f.write("追加的第四行内容\n")
f.close()

# 验证追加结果
f_read = open('./write_test.txt', mode='r', encoding='utf-8')
print("追加写入后的内容:")
print(f_read.read())
f_read.close()

3. 写入多行(writelines())

将列表中的字符串逐行写入文件(需手动加换行符\n)。

# 示例:批量写入多行
lines = ["苹果\n", "香蕉\n", "橙子\n"]
f = open('./fruit.txt', mode='w', encoding='utf-8')

f.writelines(lines)
f.close()

# 验证结果
f_read = open('./fruit.txt', mode='r', encoding='utf-8')
print("批量写入后的内容:")
print(f_read.read())
f_read.close()

五、文件关闭:必须执行的收尾操作

打开文件后,若不执行close(),会导致:

  1. 文件资源被占用,其他程序无法操作该文件;
  2. 写入的内容可能未真正保存到磁盘(Python缓存机制);
  3. 长期运行的程序可能出现“文件句柄泄露”,导致系统资源耗尽。

1. 手动关闭(close())

最基础的方式,操作完成后显式调用close()

f = open('./test.txt', mode='r', encoding='utf-8')
content = f.read()
f.close()  # 手动关闭,必须写

2. 自动关闭(with语句,推荐)

Python提供with上下文管理器,代码块执行完毕后自动关闭文件,无需手动调用close(),是最安全的方式。

# 示例1:读取文件(自动关闭)
with open('./test.txt', mode='r', encoding='utf-8') as f:
    content = f.read()
    print("with语句读取内容:", content)
# 缩进结束后,文件已自动关闭

# 示例2:写入文件(自动关闭)
with open('./with_test.txt', mode='w', encoding='utf-8') as f:
    f.write("使用with语句写入\n")
    f.write("自动关闭文件,无需手动close")

# 验证写入结果
with open('./with_test.txt', mode='r', encoding='utf-8') as f:
    print("with语句写入后的内容:")
    print(f.read())

核心优势:即使代码块中出现异常(如读取时报错),with语句也会确保文件被关闭,避免资源泄露。

六、实战案例:文件操作高频场景

案例1:统计文件行数和字符数

# 统计test.txt的行数、总字符数(不含空格)
line_count = 0
char_count = 0

with open('./test.txt', mode='r', encoding='utf-8') as f:
    for line in f:  # 直接遍历文件对象,逐行读取(最省内存)
        line_count += 1
        # 去除空格和换行符后统计字符数
        char_count += len(line.strip().replace(" ", ""))

print(f"文件总行数:{line_count}")
print(f"文件总字符数(不含空格):{char_count}")

案例2:批量替换文件中的指定内容

# 将test.txt中的"Python"替换为"Python3",保存到新文件
with open('./test.txt', mode='r', encoding='utf-8') as f_read, \
     open('./test_new.txt', mode='w', encoding='utf-8') as f_write:
    for line in f_read:
        # 替换内容
        new_line = line.replace("Python", "Python3")
        # 写入新文件
        f_write.write(new_line)

print("内容替换完成,新文件为test_new.txt")

案例3:读取大文件(GB级)的正确方式

大文件不能用read()一次性读取,需逐行遍历避免内存溢出:

# 读取GB级日志文件,筛选包含"ERROR"的行
with open('./big_log.log', mode='r', encoding='utf-8') as f:
    with open('./error_log.log', mode='w', encoding='utf-8') as f_error:
        for line in f:
            if "ERROR" in line:
                f_error.write(line)

print("ERROR日志已筛选到error_log.log")

七、常见问题与避坑指南

1. 中文乱码问题

  • 原因:打开文件时未指定encoding='utf-8',或文件本身编码不是utf-8;
  • 解决:
    1. 优先指定encoding='utf-8'
    2. 若文件是GBK编码,改为encoding='gbk'
    3. 用记事本打开文件,“另存为”选择utf-8编码。

2. 文件不存在报错(FileNotFoundError)

  • 原因:r/r+模式下文件路径错误或文件不存在;
  • 解决:
    1. 检查文件路径(绝对路径/相对路径);
    2. 若允许创建文件,改用w/a/w+/a+模式。

3. 写入内容不生效

  • 原因:未关闭文件(缓存未刷新),或用r模式写入;
  • 解决:
    1. 优先使用with语句自动刷新缓存;
    2. 手动写入后可调用f.flush()强制刷新缓存;
    3. 确认打开模式是w/a/r+等可写入模式。

4. 二进制文件操作报错

  • 原因:操作二进制文件时指定了encoding,或模式未加b
  • 解决:二进制文件用rb/wb/ab模式,且不指定encoding参数。