欢迎光临
我们一直在努力

第16课:Python|文件操作基础【文本文件读写、open函数与上下文管理器with】

在这里插入图片描述

文章目录

  • 📖 开篇导读
  • 🎯 学习目标
  • 📚 知识点理论精讲
    • 一、文件的基本概念与打开模式
      • 1.1 什么是文件
      • 1.2 `open()`函数
      • 1.3 文件打开模式详解
      • 1.4 编码问题
    • 二、读取文件的方法
      • 2.1 `read(size=-1)`
      • 2.2 `readline()`
      • 2.3 `readlines()`
      • 2.4 直接迭代文件对象(**推荐**)
    • 三、写入文件的方法
      • 3.1 `write(str)`
      • 3.2 `writelines(lines)`
      • 3.3 追加模式
      • 3.4 写入非字符串数据
    • 四、上下文管理器:`with`语句
      • 4.1 为什么需要`with`
      • 4.2 `with`的作用
      • 4.3 多个文件的`with`
    • 五、文件指针与随机访问
      • 5.1 `tell()`:返回当前指针位置(字节数)
      • 5.2 `seek(offset, whence)`
    • 六、常见异常处理
    • 七、二进制文件操作
  • 💻 代码案例实操
    • 案例1:基础文件读写——写一首诗并读取
    • 案例2:文件追加与日志记录
    • 案例3:读取大文件的正确姿势(逐行迭代)
    • 案例4:文件复制与异常处理
    • 案例5:文件指针操作与`tell`/`seek`
    • 案例6:配置文件读取与修改
    • 案例7:多文件同时操作——合并文件
  • ⚠️ 易错点避坑总结
  • 📝 课后实战练习题
      • 第1题:基本读写
      • 第2题:日志分析
      • 第3题:文件追加与搜索
      • 第4题:大文件处理
      • 第5题:复制二进制文件
      • 第6题:CSV格式读取
      • 第7题:文件加密简单版
  • 🔜 下节课预告
    • 第17课:文件进阶:二进制文件、路径处理与批量文件操作实战
  • 🔗《50节课 Python 从入门到精通》系列课程导航

📖 开篇导读

到目前为止,我们写的所有程序都是在内存中处理数据——变量在程序运行时存在,关闭程序后就会消失。这就像在白板上写字,一擦就没。但很多场景下,我们需要持久化存储数据:用户的配置信息、程序的日志、处理后的报表、爬虫抓取的内容……这些都需要保存到文件中。

Python提供了简单而强大的内置函数open()来进行文件读写。配合上下文管理器with,可以安全、优雅地操作文件,无需担心忘记关闭。

💡 工作场景:后端程序需要读取配置文件;数据分析师读取CSV文件进行处理;日志模块将运行信息写入文件;爬虫将抓取的HTML保存到本地;自动化脚本处理Excel和文本……文件操作是每个程序员的必修课。

本课我们将学习:

  • 文件的打开模式(读、写、追加、二进制等)
  • 读取文件的各种方法
  • 写入文件的多种方式
  • 上下文管理器with的使用
  • 文件指针与定位
  • 实战:文件复制、统计行数、敏感词过滤

学完本课,你将能自如地处理文本文件,实现数据的持久化存储。


🎯 学习目标

目标编号具体掌握内容对应面试/工作价值
1️⃣ 掌握open()函数的模式和编码参数 正确打开各种文件
2️⃣ 熟练使用读取方法 (read, readline, readlines) 按需读取文件内容
3️⃣ 熟练使用写入方法 (write, writelines) 保存数据到文件
4️⃣ 理解文件指针概念及seek()/tell() 随机访问文件
5️⃣ 掌握上下文管理器with,自动关闭文件 避免资源泄露
6️⃣ 了解常见异常及处理(如FileNotFoundError) 编写健壮的文件操作

🔥 面试考点:“open文件的几种模式?”“read、readline、readlines的区别?”“为什么要用with打开文件?”“如何逐行读取大文件?”


📚 知识点理论精讲

一、文件的基本概念与打开模式

1.1 什么是文件

文件是存储在外部介质(如硬盘)上的数据集合。Python通过文件对象与操作系统进行交互,完成读写操作。

1.2 open()函数

语法:

open(file, mode='r', buffering=–1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

最常用的参数:

  • file:文件路径(字符串)
  • mode:打开模式,默认'r'(只读文本)
  • encoding:编码方式,通常'utf-8'

1.3 文件打开模式详解

模式说明文件指针位置文件不存在时
'r' 只读(默认) 开头 抛出FileNotFoundError
'w' 只写(会覆盖原文件) 开头 创建新文件
'a' 追加(末尾添加) 末尾 创建新文件
'x' 独占创建,如果文件已存在则报错 开头 创建新文件
'b' 二进制模式(与r/w/a等组合,如'rb') 依据主模式 同上
't' 文本模式(默认,可与r/w/a组合,如'rt') 依据主模式 同上
'+' 读写模式(如'r+') 依据主模式 依据主模式

常用组合:

  • 'r':只读文本(最常用)
  • 'w':只写文本,覆盖已有内容
  • 'a':追加文本
  • 'rb':读取二进制文件(如图片、音频)
  • 'wb':写入二进制文件
  • 'r+':读写(指针在开头)
  • 'w+':读写,覆盖或创建
  • 'a+':读和追加,指针在末尾

🧠 通俗类比:打开文件就像打开一本笔记本。

  • 'r'(只读):你只能看,不能写。如果笔记本不存在,会报错。
  • 'w'(只写):你可以写,但会先把原来内容清空(如果笔记本存在)或新建一本。
  • 'a'(追加):你在最后面续写,不会破坏已有内容。
  • 'r+':你既可以看,也可以修改已有内容。

1.4 编码问题

文本文件有编码(如UTF-8、GBK)。Python默认使用平台编码(Windows上通常是GBK,Mac/Linux是UTF-8)。为了避免乱码,建议显式指定encoding='utf-8'。

# 正确方式
f = open('data.txt', 'r', encoding='utf-8')


二、读取文件的方法

2.1 read(size=-1)

读取指定字节数(文本模式下是字符数)。不传参数或负数,读取整个文件。

with open('data.txt', 'r', encoding='utf-8') as f:
content = f.read() # 读取全部
print(content)

注意:大文件不要使用read()不带参数,会耗尽内存。应逐行或分块读取。

2.2 readline()

读取一行(包括换行符\\n)。到达文件末尾时返回空字符串。

with open('data.txt', 'r', encoding='utf-8') as f:
line = f.readline()
while line:
print(line.strip())
line = f.readline()

2.3 readlines()

读取所有行,返回字符串列表(每行包括换行符)。

with open('data.txt', 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
print(line, end='')

2.4 直接迭代文件对象(推荐)

文件对象本身是可迭代的,可以直接for line in f:逐行读取,内存友好。

with open('data.txt', 'r', encoding='utf-8') as f:
for line in f: # 逐行读取,不会一次加载整个文件
print(line.strip())

💡 工作应用:处理大型日志文件时,必须使用逐行迭代,而不能用read()。


三、写入文件的方法

3.1 write(str)

将字符串写入文件。返回写入的字符数(可用于校验)。不会自动添加换行符。

with open('output.txt', 'w', encoding='utf-8') as f:
f.write("Hello\\n")
f.write("World\\n")

3.2 writelines(lines)

写入一个字符串列表,也不会自动添加换行符。

lines = ["第一行\\n", "第二行\\n", "第三行\\n"]
with open('output.txt', 'w', encoding='utf-8') as f:
f.writelines(lines)

3.3 追加模式

使用'a'模式,在文件末尾追加内容。

with open('log.txt', 'a', encoding='utf-8') as f:
f.write("新的日志条目\\n")

3.4 写入非字符串数据

需要先转换为字符串。

data = [1, 2, 3]
with open('nums.txt', 'w') as f:
f.write(str(data)) # 写入 "[1, 2, 3]"


四、上下文管理器:with语句

4.1 为什么需要with

传统打开文件需要手动关闭,容易遗漏导致资源泄露。

# 不推荐
f = open('data.txt', 'r')
content = f.read()
f.close() # 容易忘记

如果read()过程中发生异常,close()可能不会执行。

4.2 with的作用

with语句创建一个上下文环境,进入时执行__enter__(打开文件),退出时自动执行__exit__(关闭文件),即使发生异常也会关闭。

with open('data.txt', 'r', encoding='utf-8') as f:
content = f.read()
# 此处文件已自动关闭,无需手动close

最佳实践:始终使用with打开文件。

4.3 多个文件的with

with open('input.txt', 'r') as f_in, open('output.txt', 'w') as f_out:
data = f_in.read()
f_out.write(data.upper())


五、文件指针与随机访问

文件指针指示当前读写位置。可以使用tell()获取当前位置,seek()移动指针。

5.1 tell():返回当前指针位置(字节数)

with open('data.txt', 'r', encoding='utf-8') as f:
print(f.tell()) # 0
f.read(5)
print(f.tell()) # 5(如果每个字符1字节)

5.2 seek(offset, whence)

移动指针到指定位置。

  • whence=0(默认):相对于文件开头
  • whence=1:相对于当前位置
  • whence=2:相对于文件末尾

with open('data.txt', 'r', encoding='utf-8') as f:
f.seek(10) # 移动到第10字节
f.seek(5, 1) # 当前位置往后5字节
f.seek(–10, 2) # 从末尾往前10字节

⚠️ 注意:文本模式下,seek的偏移量必须是由tell()返回的位置(因为编码字符长度不固定)。随机访问建议使用二进制模式。


六、常见异常处理

异常触发条件处理方式
FileNotFoundError 以'r'模式打开不存在的文件 检查路径或先创建
PermissionError 无权限访问文件 修改权限或换路径
UnicodeDecodeError 编码不匹配 指定正确的encoding
IsADirectoryError 试图打开目录作为文件 检查路径是否为文件

try:
with open('missing.txt', 'r') as f:
content = f.read()
except FileNotFoundError:
print("文件不存在,请检查路径")
except PermissionError:
print("没有读取权限")


七、二进制文件操作

对于图片、音频、视频等非文本文件,使用二进制模式'rb'或'wb'。

# 复制图片
with open('source.jpg', 'rb') as src:
data = src.read()

with open('copy.jpg', 'wb') as dst:
dst.write(data)

二进制模式不需要指定编码。


💻 代码案例实操

案例1:基础文件读写——写一首诗并读取

"""
poem_file.py
演示基础的写文件和读文件
"""

# 写入文件
poem = """床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。"""

with open('poem.txt', 'w', encoding='utf-8') as f:
f.write(poem)
print("诗歌已写入 poem.txt")

# 读取整个文件
with open('poem.txt', 'r', encoding='utf-8') as f:
content = f.read()
print("\\n=== 完整内容 ===")
print(content)

# 逐行读取
print("\\n=== 逐行读取 ===")
with open('poem.txt', 'r', encoding='utf-8') as f:
for line in f:
# strip() 去掉每行末尾的换行符
print(f"行内容: {line.strip()}")

案例2:文件追加与日志记录

"""
log_writer.py
模拟日志写入,演示追加模式
"""

import datetime

def write_log(message, log_file='app.log'):
"""将带时间戳的消息追加到日志文件"""
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(log_file, 'a', encoding='utf-8') as f:
f.write(f"[{timestamp}] {message}\\n")

# 模拟多个日志
write_log("程序启动")
write_log("用户登录成功")
write_log("执行任务A")
write_log("程序正常退出")

# 读取并显示日志
print("=== 当前日志内容 ===")
with open('app.log', 'r', encoding='utf-8') as f:
for line in f:
print(line, end='')

案例3:读取大文件的正确姿势(逐行迭代)

"""
large_file_reader.py
演示如何高效读取大文件(避免内存爆炸)
"""

def count_lines(filename):
"""统计文件行数(逐行读取,不占内存)"""
count = 0
with open(filename, 'r', encoding='utf-8') as f:
for line in f: # 逐行迭代
count += 1
return count

def search_keyword(filename, keyword):
"""搜索包含关键词的行"""
matches = []
with open(filename, 'r', encoding='utf-8') as f:
for line_no, line in enumerate(f, 1):
if keyword in line:
matches.append((line_no, line.strip()))
return matches

# 模拟处理大文件(如果文件很大,不会全部读入内存)
# 实际使用时,可以传入大型日志文件
if __name__ == "__main__":
# 先创建一个小测试文件
with open('test_large.txt', 'w', encoding='utf-8') as f:
for i in range(1000):
f.write(f"这是第{i}行,内容是一些文本。\\n")

line_count = count_lines('test_large.txt')
print(f"总行数: {line_count}")

results = search_keyword('test_large.txt', '500')
print(f"找到 {len(results)} 行包含'500':")
for line_no, line in results[:3]:
print(f" 行{line_no}: {line}")

案例4:文件复制与异常处理

"""
file_copy.py
实现文件复制功能,并处理常见异常
"""

import os

def copy_file(src, dst):
"""复制文件从 src 到 dst"""
try:
# 检查源文件是否存在
if not os.path.exists(src):
raise FileNotFoundError(f"源文件不存在: {src}")

# 以二进制模式读取和写入,支持任何类型文件
with open(src, 'rb') as f_src:
data = f_src.read()

with open(dst, 'wb') as f_dst:
f_dst.write(data)

print(f"复制成功: {src} -> {dst}")
return True

except FileNotFoundError as e:
print(f"错误: {e}")
except PermissionError as e:
print(f"权限错误: {e}")
except Exception as e:
print(f"未知错误: {e}")

return False

# 测试
copy_file('poem.txt', 'poem_copy.txt')
copy_file('not_exist.txt', 'copy.txt')

案例5:文件指针操作与tell/seek

"""
file_pointer_demo.py
演示文件指针移动和随机访问
"""

# 准备示例文件
with open('test.txt', 'w', encoding='utf-8') as f:
f.write("0123456789")
f.write("ABCDEFGHIJ")

# 读取并观察指针位置
with open('test.txt', 'r', encoding='utf-8') as f:
print(f"初始位置: {f.tell()}")

data = f.read(5)
print(f"读取5个字符: '{data}', 当前位置: {f.tell()}")

# 跳到第10个字符处
f.seek(10)
print(f"seek(10)后位置: {f.tell()}")
data2 = f.read(5)
print(f"读取5个字符: '{data2}'")

# 从当前位置偏移+2
f.seek(2, 1) # 1表示相对当前位置
print(f"seek(2,1)后位置: {f.tell()}")
data3 = f.read(3)
print(f"读取3个字符: '{data3}'")

# 从末尾往前5个字节(注意文本模式下谨慎使用)
# f.seek(-5, 2) # 可能出错,因为文本模式编码不定长

# 二进制模式下的seek更可靠
with open('test.txt', 'rb') as f:
f.seek(–5, 2) # 从末尾往前5个字节
last_bytes = f.read()
print(f"最后5字节内容: {last_bytes}")

案例6:配置文件读取与修改

"""
config_reader.py
模拟读取和修改配置文件(类似INI格式)
"""

# 假设有一个配置文件 config.txt
# 格式: key = value

def read_config(filename):
"""读取配置文件,返回字典"""
config = {}
try:
with open(filename, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
if '=' in line:
key, value = line.split('=', 1)
config[key.strip()] = value.strip()
except FileNotFoundError:
print(f"配置文件 {filename} 不存在,将创建新文件")
return config

def write_config(filename, config):
"""将配置字典写入文件"""
with open(filename, 'w', encoding='utf-8') as f:
f.write("# 配置文件\\n")
for key, value in config.items():
f.write(f"{key} = {value}\\n")
print(f"配置已保存到 {filename}")

# 使用示例
config_file = 'myapp.ini'

# 读取现有配置
config = read_config(config_file)
print("当前配置:", config)

# 修改或添加配置
config['username'] = 'admin'
config['debug'] = 'true'
config['timeout'] = '30'

# 写回文件
write_config(config_file, config)

# 再次读取验证
new_config = read_config(config_file)
print("更新后配置:", new_config)

案例7:多文件同时操作——合并文件

"""
file_merger.py
合并多个文本文件的内容到一个文件
"""

def merge_files(input_files, output_file):
"""将多个文件按顺序合并到一个输出文件"""
with open(output_file, 'w', encoding='utf-8') as out_f:
for file_path in input_files:
try:
with open(file_path, 'r', encoding='utf-8') as in_f:
out_f.write(f"— 文件: {file_path} —\\n")
out_f.write(in_f.read())
out_f.write("\\n\\n") # 间隔
print(f"已合并: {file_path}")
except FileNotFoundError:
print(f"警告: 文件 {file_path} 不存在,跳过")

# 准备测试文件
for i in range(1, 4):
with open(f'part{i}.txt', 'w', encoding='utf-8') as f:
f.write(f"这是第{i}部分的内容。\\n" * 3)

# 合并
merge_files(['part1.txt', 'part2.txt', 'part3.txt'], 'merged.txt')

# 查看结果
print("\\n=== 合并后的文件内容 ===")
with open('merged.txt', 'r', encoding='utf-8') as f:
print(f.read())


⚠️ 易错点避坑总结

序号坑点描述后果解决方案
1 忘记指定encoding,导致跨平台兼容问题 中文乱码或UnicodeDecodeError 明确使用encoding='utf-8'
2 使用'w'模式时误删原有内容 文件被覆盖,数据丢失 需要保留原内容用'a'或先读取再写入
3 大文件用read()不带参数 内存溢出 逐行迭代或分块读取
4 忘记关闭文件(不用with) 资源泄露,可能写不完整 始终使用with语句
5 文本模式下使用seek随机访问 位置错误或因编码报错 二进制模式使用seek,文本模式少用
6 写入时忘记添加换行符\\n 所有内容挤在一行 显式添加\\n或使用print(file=f)
7 路径中使用反斜杠\\ 转义错误(如\\t、\\n) 使用原始字符串r"path"或正斜杠/
8 异常处理过于宽泛 隐藏其他错误 捕获具体异常(如FileNotFoundError)
9 同时读写同一个文件时未使用+模式 写入后读不到新内容(指针位置问题) 正确使用seek或分开操作
10 二进制文件写入字符串(忘记encode) TypeError 二进制模式写入bytes,或使用wb+encode

📝 课后实战练习题

第1题:基本读写

编写程序,创建一个todo.txt文件,写入以下内容:

买菜
写报告
学习Python

然后读取并逐行打印,每行前显示行号(从1开始)。

第2题:日志分析

假设有一个access.log文件,每行格式:时间 IP 请求方法 状态码。编写程序:

  • 统计状态码为404的行数
  • 找出所有IP地址(去重)
  • 输出次数最多的IP地址

(你可以先创建一个小型测试日志文件,包含10-20行模拟数据)

第3题:文件追加与搜索

编写一个电话本管理程序:

  • 支持添加联系人(姓名,电话)到contacts.txt,格式:姓名|电话
  • 支持根据姓名查找并显示电话
  • 支持删除联系人(先读取全部,删除匹配行后再写回)

第4题:大文件处理

生成一个包含100000行的大文件(每行一个随机整数),然后编写程序:

  • 统计文件中所有数字的总和
  • 找出最大值和最小值
  • 要求使用逐行读取,不能一次性读入内存

第5题:复制二进制文件

编写一个函数copy_binary(src, dst, chunk_size=1024),使用分块读写(每次读取chunk_size字节)来复制文件,适用于任意大小文件。对比一次性read()和分块读写的效率(可选)。

第6题:CSV格式读取

假设有一个students.csv文件,内容如下:

姓名,年龄,分数
张三,18,85
李四,19,92
王五,18,78

编写程序读取该文件,将每行转换为字典(如{"姓名":"张三","年龄":18,"分数":85}),然后计算平均分数。

第7题:文件加密简单版

编写一个程序,读取文本文件plain.txt,对每个字符进行简单的移位加密(如每个字母后移3位,非字母不变),将加密结果写入encrypted.txt。再编写一个解密程序,将encrypted.txt恢复为原内容。

🔜 下节课预告

掌握了文本文件的基础操作后,下一节课我们将深入文件处理的进阶内容:二进制文件、路径处理以及批量文件操作。

第17课:文件进阶:二进制文件、路径处理与批量文件操作实战

内容包括:

  • 二进制文件的读写(图片、音频、视频)
  • os和pathlib模块处理路径
  • 文件和目录的创建、删除、重命名
  • glob和os.walk批量遍历文件
  • 实战:批量重命名文件、按扩展名分类、自动备份

文件操作与系统交互是自动化脚本的核心,学完你将能编写实用的文件管理工具。

🌟 学习鼓励:文件操作是编程中非常实用的技能。你可能会遇到各种编码错误、路径问题,但请耐心调试——多练习几次,你就会掌握其中的规律。特别是with语句,一定要养成习惯。下一课的批量文件操作会让你的工作效率倍增!


🔗《50节课 Python 从入门到精通》系列课程导航

去订阅

🌟 感谢您耐心阅读到这里! 💡 如果本文对您有所启发欢迎: 👍 点赞📌 收藏 📤 分享给更多需要的伙伴。 🗣️ 期待在评论区看到您的想法, 共同进步。 🔔 关注我,持续获取更多干货内容~ 🤗 我们下篇文章见~

赞(0)
未经允许不得转载:171主机测评 » 第16课:Python|文件操作基础【文本文件读写、open函数与上下文管理器with】
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址