本文总结了Python文件读写的核心API及注意事项。
主要内容包括:
1)文件打开与关闭方法,推荐使用with语句自动管理资源;
2)文件读取方法,如read()、readline()等,注意大文件应使用迭代器方式;
3)文件写入方法及操作模式说明;
4)文件指针操作和常用辅助参数设置。
最佳实践建议:始终使用with语句,明确指定编码,根据场景选择合适方法(如大文件用迭代器)。
常见错误包括编码问题、文件指针位置错误等,可通过指定正确编码、seek(0)重置指针等方式解决。
使用Python进行文件读写的API或方法及其注意事项
以下是 Python 文件读写的核心 API 及注意事项总结表:
一、文件打开与关闭
| API/方法 | 功能说明 | 示例 | 注意事项 |
|---|---|---|---|
open(file, mode, encoding) |
打开文件,返回文件对象 | f = open('test.txt', 'r', encoding='utf-8') |
1. 必须指定正确的编码(如 utf-8) 2. 文件不存在时 'r' 模式会报错 FileNotFoundError 3. 建议使用 with 语句自动管理资源 |
close() |
关闭文件对象 | f.close() |
1. 忘记关闭可能导致内存泄漏或数据丢失 2. 已关闭的文件无法再进行读写操作 3. 使用 with 语句可自动调用 |
with 语句 |
上下文管理器,自动关闭文件 | with open('test.txt', 'r') as f: |
推荐使用,即使发生异常也会自动关闭文件 |
二、文件读取方法
| API/方法 | 功能说明 | 返回值 | 注意事项 |
|---|---|---|---|
read(size=-1) |
读取指定字节数,默认读取全部 | 字符串 | 1. 大文件不建议无参读取,会耗尽内存 2. 读取后文件指针移动到末尾 3. 再次调用返回空字符串 |
readline(size=-1) |
读取一行 | 字符串(包含换行符 \n) |
1. 文件末尾返回空字符串 '' 2. 换行符会被保留 3. 可用 strip() 去除换行符 |
readlines(hint=-1) |
读取所有行 | 字符串列表(每行含 \n) |
1. 大文件同样有内存风险 2. 可用 for line in f: 逐行迭代更高效 |
| 迭代器方式 | 逐行读取(内存友好) | 每行字符串 | for line in f: process(line) *** ** * ** *** 推荐大文件使用,不会一次性加载全部内容 |
三、文件写入方法
| API/方法 | 功能说明 | 示例 | 注意事项 |
|---|---|---|---|
write(str) |
写入字符串 | f.write('Hello\n') |
1. 不会自动添加换行符,需手动加 \n 2. 返回写入的字符数 3. 需要配合 flush() 或 close() 确保写入磁盘 |
writelines(lines) |
写入字符串列表 | f.writelines(['a\n', 'b\n']) |
1. 不会自动添加换行符 2. 需要自己保证每个元素末尾有 \n 3. 适用于批量写入 |
flush() |
强制刷新缓冲区 | f.flush() |
立即将缓冲区数据写入磁盘,避免数据丢失 |
四、文件操作模式
| 模式 | 说明 | 文件指针位置 | 文件不存在 | 原有内容 |
|---|---|---|---|---|
'r' |
只读(默认) | 文件开头 | 报错 FileNotFoundError |
保留 |
'w' |
只写(覆盖) | 文件开头 | 创建新文件 | 清空 |
'a' |
追加 | 文件末尾 | 创建新文件 | 保留 |
'x' |
独占创建 | 文件开头 | 创建新文件 | 不存在(文件存在则报错) |
'r+' |
读写 | 文件开头 | 报错 | 保留(从头覆盖) |
'w+' |
读写(覆盖) | 文件开头 | 创建新文件 | 清空 |
'a+' |
读追加 | 文件末尾 | 创建新文件 | 保留 |
'b' |
二进制模式 | 视主模式而定 | 视主模式而定 | 与文本模式配合使用,如 'rb', 'wb' |
五、文件指针操作
| API/方法 | 功能说明 | 示例 | 注意事项 |
|---|---|---|---|
tell() |
返回当前指针位置(字节数) | pos = f.tell() |
1. 文本模式下可能不准确(多字节字符) 2. 二进制模式更可靠 |
seek(offset, whence) |
移动文件指针 | f.seek(0, 0) 移到开头 |
1. whence: 0=开头,1=当前位置,2=末尾 2. 文本模式只支持 whence=0 3. offset 需配合 tell() 返回值 |
六、常用辅助操作
| API/方法 | 功能说明 | 示例 | 注意事项 |
|---|---|---|---|
encoding 参数 |
指定文件编码 | encoding='utf-8' |
1. 必须指定,避免平台依赖 2. 常用编码:utf-8, gbk, gb2312 |
errors 参数 |
处理编码错误 | errors='ignore' 或 'replace' |
1. 'ignore' 忽略错误 2. 'replace' 用 ? 替换 3. 'strict' 抛出异常(默认) |
newline 参数 |
控制换行符处理 | newline='' |
1. 读写 CSV 时建议设为 '' 2. 避免跨平台换行符问题 |
七、最佳实践总结
| 场景 | 推荐方法 | 示例代码 |
|---|---|---|
| 读小文件(<100MB) | read() |
data = f.read() |
| 读大文件 | 迭代器 | for line in f: process(line) |
| 读配置文件 | readlines() 或迭代 |
lines = f.readlines() |
| 写少量数据 | write() |
f.write('data') |
| 写大量数据 | writelines() |
f.writelines(lines) |
| 需要随机访问 | seek() + tell() |
配合二进制模式使用 |
| 二进制文件(图片等) | 'rb' / 'wb' |
f.read(1024) 分块读取 |
| 自动资源管理 | with 语句 |
始终推荐 |
八、常见错误与解决方案
| 错误类型 | 典型错误信息 | 解决方案 |
|---|---|---|
| 编码错误 | 'gbk' codec can't decode... |
指定正确的 encoding 参数 |
| 文件不存在 | FileNotFoundError |
检查路径或使用 'w'/'a' 模式 |
| 权限错误 | PermissionError |
关闭其他程序占用,检查文件只读属性 |
| 指针错误 | 读到空数据 | 检查是否在 read() 后忘了 seek(0) |
| 换行符问题 | 写入内容挤在一行 | 手动添加 \n 或使用 print(file=f) |
九、典型完整示例
python
# 推荐的标准写法
with open('file.txt', 'r', encoding='utf-8') as f:
for line in f: # 逐行读取,内存友好
print(line.strip())
# 写入示例
with open('output.txt', 'w', encoding='utf-8') as f:
f.write('第一行\n')
f.writelines(['第二行\n', '第三行\n'])
# 无需手动 close()
这个表格涵盖了 Python 文件操作的主要 API 和使用要点,建议在实际开发中优先使用 with 语句并明确指定编码。
补充:文件操作模式
以下是 Python 文件操作模式的完整补充,包括所有组合模式及详细说明:
一、基础模式完整版
| 模式 | 读写权限 | 文件指针位置 | 文件不存在 | 原有内容处理 | 典型应用场景 |
|---|---|---|---|---|---|
'r' |
只读 | 开头 | 报错 | 保留 | 读取配置文件、日志分析 |
'w' |
只写 | 开头 | 创建 | 清空 | 生成新文件、覆盖旧数据 |
'a' |
只写 | 末尾 | 创建 | 保留 | 日志记录、追加数据 |
'x' |
只写 | 开头 | 创建(独占) | 不存在 | 防止覆盖、创建锁文件 |
'r+' |
读写 | 开头 | 报错 | 保留 | 修改文件特定位置 |
'w+' |
读写 | 开头 | 创建 | 清空 | 需要读写的全新文件 |
'a+' |
读写 | 末尾 | 创建 | 保留 | 追加并读取(如日志分析) |
二、二进制模式组合
| 模式 | 说明 | 数据类型 | 换行符处理 | 典型应用 |
|---|---|---|---|---|
'rb' |
二进制只读 | bytes | 无转换 | 图片、视频、PDF、压缩包 |
'wb' |
二进制只写 | bytes | 无转换 | 保存图片、序列化数据 |
'ab' |
二进制追加 | bytes | 无转换 | 合并二进制文件 |
'xb' |
二进制独占创建 | bytes | 无转换 | 避免覆盖二进制文件 |
'rb+' |
二进制读写 | bytes | 无转换 | 修改二进制文件特定字节 |
'wb+' |
二进制读写(覆盖) | bytes | 无转换 | 创建可读写的二进制文件 |
'ab+' |
二进制读写(追加) | bytes | 无转换 | 追加并读取二进制数据 |
三、特殊模式组合
| 模式 | 说明 | 行为特点 | 注意事项 | 示例场景 |
|---|---|---|---|---|
'rt' |
文本只读(默认) | 同 'r' |
文本模式的标准写法 | 明确指定文本模式 |
'wt' |
文本只写 | 同 'w' |
明确指定文本模式 | 生成文本文件 |
'at' |
文本追加 | 同 'a' |
明确指定文本模式 | 日志追加 |
'U' |
通用换行模式 | 已弃用 | Python 3 中不再使用 | 历史代码兼容 |
四、模式详细行为对比
4.1 文件指针位置详解
python
# 演示不同模式的指针位置
with open('test.txt', 'w') as f:
f.write('1234567890')
# r+ 模式:指针在开头
with open('test.txt', 'r+') as f:
print(f.tell()) # 0
f.write('ABC')
f.seek(0)
print(f.read()) # ABC4567890
# a+ 模式:指针在末尾
with open('test.txt', 'a+') as f:
print(f.tell()) # 10(文件末尾)
f.write('XYZ')
f.seek(0)
print(f.read()) # ABC4567890XYZ
4.2 读写操作行为差异
| 模式 | 执行 read() |
执行 write() |
执行 seek() |
缓冲区行为 |
|---|---|---|---|---|
'r' |
✅ 可以 | ❌ 报错 | ✅ 可以 | 行缓冲 |
'w' |
❌ 报错 | ✅ 可以 | ✅ 可以 | 行缓冲 |
'a' |
❌ 报错 | ✅ 可以(始终末尾) | 可移动但写操作回到末尾 | 行缓冲 |
'r+' |
✅ 可以 | ✅ 可以(覆盖) | ✅ 可以 | 行缓冲 |
'w+' |
✅ 可以 | ✅ 可以(清空后) | ✅ 可以 | 行缓冲 |
'a+' |
✅ 可以(需先 seek) | ✅ 可以(始终末尾) | 读可移动,写强制末尾 | 行缓冲 |
4.3 错误处理行为
python
# 不同模式对错误的处理
import os
# 模式 'x' - 文件存在时报错
try:
with open('existing.txt', 'x') as f:
f.write('data')
except FileExistsError:
print("文件已存在,无法创建")
# 模式 'r' - 文件不存在时报错
try:
with open('not_exist.txt', 'r') as f:
data = f.read()
except FileNotFoundError:
print("文件不存在")
# 模式 'w' - 自动创建,不报错
with open('new_file.txt', 'w') as f:
f.write('自动创建成功')
五、平台差异性说明
| 模式 | Linux/macOS 行为 | Windows 行为 | 注意事项 |
|---|---|---|---|
| 文本模式换行符 | \n |
\r\n 自动转换 |
跨平台时注意编码 |
| 二进制模式 | 无转换 | 无转换 | 推荐处理非文本文件 |
'a' 模式 |
写操作始终末尾 | 写操作始终末尾 | Windows 某些情况有差异 |
| 文件锁定 | 通常不锁定 | 可能部分锁定 | Windows 更严格 |
六、实际应用场景示例
6.1 配置文件读写
python
# 使用 'r' 读取配置
def read_config():
with open('config.txt', 'r', encoding='utf-8') as f:
return dict(line.strip().split('=') for line in f)
# 使用 'w' 保存配置
def save_config(config):
with open('config.txt', 'w', encoding='utf-8') as f:
for key, value in config.items():
f.write(f"{key}={value}\n")
6.2 日志文件追加
python
import datetime
def log_message(msg):
# 'a' 模式自动追加,不会覆盖历史日志
with open('app.log', 'a', encoding='utf-8') as f:
timestamp = datetime.datetime.now()
f.write(f"[{timestamp}] {msg}\n")
6.3 二进制文件处理
python
# 复制图片(二进制模式)
def copy_image(src, dst):
with open(src, 'rb') as source:
with open(dst, 'wb') as target:
# 分块复制,避免内存爆炸
while chunk := source.read(8192):
target.write(chunk)
# 修改二进制文件特定位置
def patch_binary(filepath, offset, new_bytes):
with open(filepath, 'r+b') as f:
f.seek(offset)
f.write(new_bytes)
6.4 临时文件安全创建
python
# 使用 'x' 模式避免覆盖
def safe_save(data, filename):
try:
with open(filename, 'x', encoding='utf-8') as f:
f.write(data)
print(f"成功创建 {filename}")
except FileExistsError:
print(f"文件 {filename} 已存在,拒绝覆盖")
# 可以生成新文件名
base, ext = os.path.splitext(filename)
new_name = f"{base}_new{ext}"
return safe_save(data, new_name)
6.5 文件内容原地修改
python
# 使用 'r+' 模式修改文件特定行
def replace_line(filename, line_num, new_content):
with open(filename, 'r+', encoding='utf-8') as f:
lines = f.readlines()
if 0 <= line_num < len(lines):
lines[line_num] = new_content + '\n'
f.seek(0)
f.writelines(lines)
f.truncate() # 截断多余内容
6.6 CSV 文件处理
python
import csv
# 读取 CSV(文本模式)
def read_csv(filename):
with open(filename, 'r', newline='', encoding='utf-8') as f:
return list(csv.reader(f))
# 写入 CSV(文本模式)
def write_csv(filename, data):
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerows(data)
七、高级模式与标志位(底层 os.open)
| os 标志 | 说明 | Python 等效 | 用途 |
|---|---|---|---|
os.O_RDONLY |
只读 | 'r' |
底层文件操作 |
os.O_WRONLY |
只写 | 'w' |
底层文件操作 |
os.O_RDWR |
读写 | 'r+' |
底层文件操作 |
os.O_CREAT |
不存在则创建 | 'w', 'a' |
自动创建 |
os.O_EXCL |
与 O_CREAT 配合独占创建 |
'x' |
原子性创建 |
os.O_TRUNC |
截断文件 | 'w' |
清空内容 |
os.O_APPEND |
追加模式 | 'a' |
原子性追加 |
os.O_SYNC |
同步写入 | 无直接等效 | 性能与可靠性平衡 |
八、性能对比与选择建议
| 场景 | 推荐模式 | 性能特点 | 理由 |
|---|---|---|---|
| 大文件只读 | 'r' |
高 | 利用系统缓存 |
| 频繁小写入 | 'a' |
中 | 避免重复 seek |
| 随机读写 | 'r+b' |
低 | 需要多次 seek |
| 日志追加 | 'a' |
高 | 原子性操作 |
| 临时文件 | 'x' |
高 | 避免冲突 |
| 二进制拷贝 | 'rb', 'wb' |
高 | 无编码转换开销 |
九、常见陷阱与解决方案
| 陷阱 | 表现 | 解决方案 |
|---|---|---|
| 忘记二进制模式 | 图片读写乱码 | 使用 'rb'/'wb' |
'a+' 读不到数据 |
read() 返回空 |
先 seek(0) 再读 |
'r+' 意外覆盖 |
写入位置不对 | 精确使用 seek() |
'w' 清空数据 |
原有数据丢失 | 改用 'a' 或备份 |
| 换行符混乱 | Windows 下 \r\n 问题 |
二进制模式或指定 newline |
十、完整决策树
python
# 选择文件模式的决策逻辑
def choose_mode(read_needed, write_needed, append_mode, binary_mode, safe_create):
if binary_mode:
mode_base = 'b'
else:
mode_base = 't' # 可省略
if read_needed and write_needed:
if safe_create:
return 'w+' + mode_base # 安全创建但会清空
elif append_mode:
return 'a+' + mode_base
else:
return 'r+' + mode_base
elif read_needed:
return 'r' + mode_base
elif write_needed:
if safe_create:
return 'x' + mode_base
elif append_mode:
return 'a' + mode_base
else:
return 'w' + mode_base
else:
raise ValueError("至少需要读或写权限")
# 使用示例
print(choose_mode(True, False, False, False, False)) # 'r'
print(choose_mode(True, True, True, False, False)) # 'a+'
print(choose_mode(False, True, False, True, False)) # 'wb'
print(choose_mode(False, True, False, False, True)) # 'x'
这个补充涵盖了 Python 文件操作模式的所有细节,建议根据具体场景选择合适的模式组合。
错误示例:错误分析
python
#读文件
with open("C:\\Users\\86178\\Desktop\\aaa.txt",'r',encoding="utf-8") as f:
con=f.read()#将文本的内容作为一个整体字符串,读出来
con1=f.readline()
con2 = f.readlines()#把文本每行的内容 作为一个元素 放到列表里面
print(con)
#输出
# aaa
# bbb
# ccc
print(con1)#换行?
print(con2)#[]?
f.close()#关闭该线程 关闭文件
你的代码存在一个关键问题 :在调用了 f.read() 之后,文件指针已经移动到了文件末尾,因此后续的 f.readline() 和 f.readlines() 无法再读取到任何内容。
问题分析
-
f.read()读取整个文件,指针移到最后 -
f.readline()从当前位置(文件末尾)读取,返回空字符串'' -
f.readlines()同样从末尾读取,返回空列表[] -
你看到的
print(con1)输出空行,是因为打印了空字符串后自动换行 -
f.close()其实可以省略(with语句会自动关闭)
修正后的代码
方案一:只使用一种读取方式
python
with open("C:\\Users\\86178\\Desktop\\aaa.txt", 'r', encoding="utf-8") as f:
con = f.read() # 整体读取
print(con)
方案二:分别读取(需要重新打开或重置指针)
python
with open("C:\\Users\\86178\\Desktop\\aaa.txt", 'r', encoding="utf-8") as f:
con = f.read()
print("read()结果:")
print(con)
# 将指针移回文件开头
f.seek(0)
con1 = f.readline()
print("readline()结果:", repr(con1)) # 使用repr可以看到转义字符
con2 = f.readlines()
print("readlines()结果:", con2)
方案三:分别打开文件
python
# 分别演示三种读取方式
with open("C:\\Users\\86178\\Desktop\\aaa.txt", 'r', encoding="utf-8") as f:
print("1. read():")
print(f.read())
with open("C:\\Users\\86178\\Desktop\\aaa.txt", 'r', encoding="utf-8") as f:
print("\n2. readline():")
print(repr(f.readline()))
with open("C:\\Users\\86178\\Desktop\\aaa.txt", 'r', encoding="utf-8") as f:
print("\n3. readlines():")
print(f.readlines())
补充说明
-
readline():返回一行字符串(包含换行符\n),文件末尾返回空字符串'' -
readlines():返回所有行的列表,每行字符串包含换行符 -
repr()函数可以显示字符串的真实内容,包括\n等转义字符 -
seek(0):将文件指针移动到指定位置,0表示文件开头
类似错误
python
with open('day_07.py','w+',encoding="utf-8") as f:
f.writelines("hello world\n")#覆盖写入
con = f.read()
print(con)#为什么读不出数据?
f.close()
问题在于文件指针位置!你的代码流程如下:
问题分析
python
with open('day_07.py', 'w+', encoding="utf-8") as f:
f.writelines("hello world\n") # 1. 写入数据,指针在末尾(第13个字节后)
con = f.read() # 2. 从末尾读取 → 读不到任何数据
print(con) # 3. 输出空字符串
f.close() # 4. with 语句会自动关闭,此行多余
关键点:
-
writelines()写入后,文件指针停留在写入内容的末尾 -
此时调用
read(),从末尾开始读 → 返回空字符串
解决方案
方案一:先 seek(0) 再读取
python
with open('day_07.py', 'w+', encoding="utf-8") as f:
f.writelines("hello world\n")
f.seek(0) # 将指针移回文件开头
con = f.read()
print(con) # 输出: hello world
方案二:先写入,关闭后重新读取
python
# 先写入
with open('day_07.py', 'w', encoding="utf-8") as f:
f.writelines("hello world\n")
# 再读取
with open('day_07.py', 'r', encoding="utf-8") as f:
con = f.read()
print(con) # 输出: hello world
方案三:使用 r+ 模式(需要文件已存在)
python
# 先创建文件
with open('day_07.py', 'w', encoding="utf-8") as f:
f.writelines("hello world\n")
# 再读写
with open('day_07.py', 'r+', encoding="utf-8") as f:
con = f.read()
print(con) # 输出: hello world
f.write("\n追加内容") # 在末尾追加
各模式写入后的指针位置
| 模式 | 写入操作 | 写入后指针位置 | 立即读取结果 |
|---|---|---|---|
'w+' |
write() / writelines() |
文件末尾 | 空字符串(需 seek(0)) |
'r+' |
write() |
写入位置末尾(可能覆盖) | 取决于写入位置 |
'a+' |
write() |
始终在文件末尾 | 空字符串(需 seek(0)) |
'w' |
write() |
文件末尾 | 不支持读取 |
验证指针位置
python
# 演示指针位置变化
with open('day_07.py', 'w+', encoding="utf-8") as f:
print(f"初始位置: {f.tell()}") # 0
f.writelines("hello world\n")
print(f"写入后位置: {f.tell()}") # 13(假设12个字符+换行符)
f.seek(0)
print(f"seek(0)后位置: {f.tell()}") # 0
con = f.read()
print(f"读取后位置: {f.tell()}") # 13(读完又到末尾)
print(f"读取内容: {con}") # hello world
正确的 w+ 使用场景
w+ 模式适合以下场景:
场景1:写入后立即读取(需 seek)
python
with open('temp.txt', 'w+', encoding="utf-8") as f:
# 生成数据
for i in range(10):
f.write(f"第{i}行\n")
# 需要读取时,先回到开头
f.seek(0)
data = f.read()
print(data)
场景2:清空文件后重新写入并验证
python
with open('config.txt', 'w+', encoding="utf-8") as f:
f.write("new config data")
f.seek(0)
# 验证写入是否正确
if f.read() == "new config data":
print("写入成功")
场景3:在内存中处理数据
python
# 使用 StringIO 更好,但 w+ 也可以
with open('data.txt', 'w+', encoding="utf-8") as f:
# 先生成内容
lines = ["line1\n", "line2\n", "line3\n"]
f.writelines(lines)
# 处理这些数据
f.seek(0)
processed = [line.upper() for line in f]
print(processed) # ['LINE1\n', 'LINE2\n', 'LINE3\n']
其他注意事项
1. close() 是多余的
python
# with 语句会自动关闭文件,不需要手动 close()
with open('day_07.py', 'w+', encoding="utf-8") as f:
f.write("data")
f.seek(0)
print(f.read())
# 离开 with 块时自动关闭
2. writelines() 不会自动换行
python
# writelines() 不会自动添加换行符
with open('test.txt', 'w+') as f:
f.writelines(["hello", "world"]) # 结果是 "helloworld"
# 需要手动添加
with open('test.txt', 'w+') as f:
f.writelines(["hello\n", "world\n"]) # 正确
3. 更清晰的替代方案
python
# 如果只是创建新文件并写入,用 'w' 模式
with open('day_07.py', 'w', encoding="utf-8") as f:
f.writelines("hello world\n")
# 单独读取
with open('day_07.py', 'r', encoding="utf-8") as f:
print(f.read())
总结
你的代码读不出数据的原因 :writelines() 后指针在文件末尾,read() 从末尾开始读导致返回空字符串。
解决方法 :在读取前添加 f.seek(0) 将指针移回开头。
最佳实践 :除非确实需要读写切换,否则建议使用单一目的的模式 ('r' 只读或 'w' 只写),代码意图更清晰。