Python 文件操作完全指南
概述
Python 文件操作是每个 Python 开发者必备的基础技能,涵盖了从读取本地文本文件、处理 CSV/JSON 数据格式,到管理二进制文件(图片、音视频)等常见场景。Python 内置的 open() 函数和相关模块(os、shutil、pathlib)提供了完整文件操作能力,无需依赖第三方库即可完成大多数文件处理任务。
基础语法
Python 文件操作最核心的是 open() 函数,它接受文件路径、打开模式(mode)和编码(encoding)三个主要参数。打开模式决定了能做什么操作:r=只读,w=只写(覆盖),a=追加,r+=读写。文件对象支持两种使用方式——手动 close() 关闭,或者用 with 语句自动管理资源(推荐)。
- r:只读模式,文件不存在会报错。
- w:只写模式,文件存在则覆盖,不存在则创建。
- a:追加模式,在文件末尾添加内容。
- b:二进制模式,与 r/w/a 组合使用,如 rb、wb。
- x:新建模式,文件存在则报错,适合创建新文件。
pathlib 是 Python 3.4 引入的面向对象路径操作模块,用 Path 对象表示文件路径,比传统的 os.path 函数更直观易读。
完整代码示例+注释
import os
import shutil
import json
from pathlib import Path
=== 基础文件读写 ===
使用 with 语句自动管理文件资源(推荐)
with open('example.txt', 'w', encoding='utf-8') as f:
f.write('第一行:你好,世界!
')
f.write('第二行:Python 文件操作演示
')
读取文件内容
with open('example.txt', 'r', encoding='utf-8') as f:
content = f.read() # 一次性读取全部
print(content)
按行读取,适合大文件
with open('example.txt', 'r', encoding='utf-8') as f:
for line in f: # 迭代器方式,内存友好
print(line.rstrip())
=== JSON 文件操作 ===
data = {
'name': '张三',
'age': 28,
'skills': ['Python', 'JavaScript', 'Docker'],
'experience': [
{'company': 'A公司', 'years': 2},
{'company': 'B公司', 'years': 3}
]
}
写入 JSON 文件(格式化输出)
with open('user.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
读取 JSON 文件
with open('user.json', 'r', encoding='utf-8') as f:
loaded = json.load(f)
print(f"姓名: {loaded['name']}, 技能数: {len(loaded['skills'])}")
=== pathlib 面向对象操作(推荐) ===
base = Path('/home/ubuntu/projects')
检查路径是否存在
if (base / 'README.md').exists():
print('README.md 已存在')
创建目录( parents=True 递归创建,exist_ok=True 忽略已存在)
(base / 'output' / 'logs').mkdir(parents=True, exist_ok=True)
遍历目录下的所有 .py 文件
for py_file in base.rglob('*.py'): # rglob 递归匹配
size = py_file.stat().st_size
print(f"{py_file.relative_to(base)}: {size} bytes")
=== 文件复制、移动、删除 ===
src = Path('source.txt')
dst = Path('backup/source_backup.txt')
if src.exists():
shutil.copy2(src, dst) # copy2 保留元数据(修改时间等)
print(f'已复制到 {dst}')
移动/重命名
shutil.move('old_name.txt', 'new_name.txt')
删除文件(谨慎使用)
Path('temp.txt').unlink() # 删除单个文件
Path('temp_dir').rmdir() # 删除空目录
=== 二进制文件操作 ===
读取图片并复制
with open('photo.jpg', 'rb') as f:
data = f.read()
print(f'图片大小: {len(data) / 1024:.1f} KB')
安全写入二进制
with open('photo_copy.jpg', 'wb') as f:
f.write(data)
=== 文件锁(多进程访问同一文件时) ===
import fcntl
with open('shared.txt', 'a') as f:
fcntl.flock(f.fileno(), fcntl.LOCK_EX) # 加独占锁
f.write('进程安全写入
')
fcntl.flock(f.fileno(), fcntl.LOCK_UN) # 解锁
运行效果
执行上述代码,会依次创建 example.txt(包含两行文本)、user.json(格式化的 JSON 数据)、photo_copy.jpg(图片副本)。pathlib 的 rglob('*.py') 会递归查找所有 Python 文件并打印相对路径和大小。文件锁示例在多进程场景下确保同一时刻只有一个进程能写入 shared.txt,避免数据竞争导致的内容损坏。
使用 with open() 管理文件资源是最佳实践,即使代码在读写过程中抛出异常,文件也会被正确关闭,不会造成资源泄漏。对于大文件处理(如日志分析、CSV 数据导入数据库),建议使用迭代器方式逐行读取,而非一次性 load 到内存。
常见问题
Q1:写入中文内容时出现编码错误
Python 3 默认使用 UTF-8 编码,在 open() 时显式传入 encoding='utf-8' 即可。如果文件不是 UTF-8 编码(如 Windows 常见的 GBK),需要指定对应编码如 encoding='gbk'。遇到编码问题可以用 chardet 库自动检测文件编码。
Q2:使用 shutil.rmtree 删除目录时如何避开只读文件
shutil.rmtree 在遇到只读文件时会报错。解决方案是先遍历目录,将所有文件改为可写属性后再删除,或者使用 onerror 参数传入一个回调函数处理错误:shutil.rmtree(path, onerror=lambda fn, p, e: os.chmod(p, 0o777) or fn(p))。
Q3:pathlib 的 Path 对象如何转换为字符串
直接用 str() 转换:str(Path('/home/a.txt'))。如果要获取纯文件名用 Path.name,需要去掉扩展名用 Path.stem,获取父目录用 Path.parent。在需要路径字符串的地方(如 open()、os.path 函数),pathlib 通常可以自动转换。
Q4:文件写入后立即读取为什么内容不完整
这通常是缓冲区的缘故。写入的数据可能还在 Python 的缓冲区中,没有真正写到磁盘。调用 f.flush() 强制刷新缓冲区,或者用 with 语句结束时自动关闭文件。另一个可能是文件被多个进程或线程同时读写,需要加文件锁。
延伸阅读
- Python 官方文件操作文档:https://docs.python.org/zh-cn/3/library/io.html — 包含 BufferedReader/BufferedWriter 等高级文件对象的说明。
- pathlib 官方文档:https://docs.python.org/zh-cn/3/library/pathlib.html — 完整的 Path API 参考。
- Python csv 模块:内置的 CSV 文件读写模块,支持方言(delimiter、quoting 等)配置。