本文总结了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'模式会报错FileNotFoundError3. 建议使用 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. 不会自动添加换行符,需手动加\n2. 返回写入的字符数 3. 需要配合 flush()或close()确保写入磁盘 |
writelines(lines) | 写入字符串列表 | f.writelines(['a\n', 'b\n']) | 1. 不会自动添加换行符 2. 需要自己保证每个元素末尾有 \n3. 适用于批量写入 |
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=03. 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()) # ABC4567890XYZ4.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 文件操作模式的所有细节,建议根据具体场景选择合适的模式组合。
错误示例:错误分析
#读文件 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表示文件开头
类似错误
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'只写),代码意图更清晰。