1. Python文件I/O基础概念解析
文件I/O(输入/输出)是Python编程中最基础也最常用的功能之一。简单来说,就是让程序能够读取外部文件的数据,或者将程序运行结果保存到文件中。这就像我们日常使用记事本一样,只不过现在是用代码来操作。
在实际开发中,文件操作的应用场景非常广泛:
- 读取配置文件(如JSON、INI格式)
- 处理日志文件
- 数据持久化存储
- 批量处理文本数据
- 与其他程序交换数据
Python提供了非常简洁的文件操作API,主要涉及以下几个核心函数和方法:
- open():打开文件
- read()/readline()/readlines():读取内容
- write()/writelines():写入内容
- close():关闭文件
重要提示:文件操作完成后一定要记得关闭文件,否则可能会导致数据丢失或文件损坏。Python的with语句可以自动处理文件关闭,是更推荐的做法。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 文件操作基础:打开、读取和写入
2.1 文件打开模式详解
Python的open()函数是文件操作的起点,它的完整语法是:
python复制open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
最常用的参数是file(文件路径)和mode(打开模式)。mode参数决定了文件如何被处理:
| 模式 | 描述 | 文件不存在时 |
|---|---|---|
| 'r' | 只读(默认) | 报错 |
| 'w' | 写入(覆盖) | 创建新文件 |
| 'x' | 独占创建 | 报错 |
| 'a' | 追加写入 | 创建新文件 |
| 'b' | 二进制模式 | - |
| 't' | 文本模式(默认) | - |
| '+' | 更新(可读可写) | - |
模式可以组合使用,例如:
- 'rb':以二进制只读模式打开
- 'w+':可读可写,清空文件内容
- 'a+':可读可写,追加模式
2.2 文件读取方法对比
Python提供了多种读取文件内容的方法,各有适用场景:
- read():一次性读取全部内容
python复制with open('example.txt', 'r') as f:
content = f.read() # 返回整个文件内容的字符串
- readline():逐行读取
python复制with open('example.txt', 'r') as f:
line = f.readline() # 每次读取一行
while line:
print(line, end='')
line = f.readline()
- readlines():读取所有行到列表
python复制with open('example.txt', 'r') as f:
lines = f.readlines() # 返回包含所有行的列表
- 直接迭代文件对象(内存效率最高)
python复制with open('example.txt', 'r') as f:
for line in f: # 逐行迭代,不一次性加载全部内容
print(line, end='')
性能提示:处理大文件时,推荐使用逐行迭代的方式,可以避免内存不足的问题。
2.3 文件写入技巧
写入文件同样有多种方式:
- write():写入字符串
python复制with open('output.txt', 'w') as f:
f.write('Hello, World!\n') # 注意手动添加换行符
- writelines():写入字符串列表
python复制lines = ['第一行\n', '第二行\n', '第三行\n']
with open('output.txt', 'w') as f:
f.writelines(lines) # 列表中的每个元素会被依次写入
- 打印到文件
python复制with open('output.txt', 'w') as f:
print('Hello', 'World', sep=', ', file=f) # 使用print函数写入
写入时需要注意:
- 'w'模式会清空文件原有内容
- 换行符需要手动添加(\n)
- 写入前确保目录存在,否则会报错
3. 高级文件操作技巧
3.1 上下文管理器与with语句
Python的with语句是处理文件的最佳实践,它可以确保文件在使用后被正确关闭,即使在操作过程中发生异常。
传统方式的问题:
python复制f = open('file.txt', 'r')
try:
data = f.read()
# 处理数据
finally:
f.close() # 必须手动关闭
使用with语句的改进:
python复制with open('file.txt', 'r') as f:
data = f.read()
# 处理数据
# 离开with块后文件自动关闭
with语句实际上使用了上下文管理器协议,任何实现了__enter__和__exit__方法的对象都可以这样使用。
3.2 文件指针操作
文件对象内部维护了一个指针,指示当前读写位置。我们可以通过tell()和seek()方法来获取和移动指针位置。
python复制with open('example.txt', 'r+') as f:
print(f.tell()) # 输出0,起始位置
content = f.read(10) # 读取前10个字符
print(f.tell()) # 输出10
f.seek(5) # 移动到第5个字符位置
print(f.tell()) # 输出5
f.write('INSERT') # 在当前位置写入
seek()方法的参数:
- seek(offset, whence=0)
- whence=0:从文件开头计算(默认)
- whence=1:从当前位置计算
- whence=2:从文件末尾计算
3.3 二进制文件操作
处理图片、音频等非文本文件时,需要使用二进制模式('b'):
python复制# 复制图片文件
with open('input.jpg', 'rb') as src, open('output.jpg', 'wb') as dst:
dst.write(src.read())
# 读取二进制文件的特定部分
with open('data.bin', 'rb') as f:
f.seek(100) # 跳到第100字节
data = f.read(50) # 读取50字节
二进制模式下:
- 读取返回bytes对象而非str
- 换行符不会自动转换
- 适合处理任意二进制数据
4. 常见文件操作场景与问题解决
4.1 处理不同编码的文本文件
编码问题是文件操作中最常见的坑之一。Python3默认使用UTF-8编码,但实际文件可能有其他编码。
python复制# 尝试读取可能不同编码的文件
encodings = ['utf-8', 'gbk', 'gb2312', 'iso-8859-1']
for enc in encodings:
try:
with open('unknown.txt', 'r', encoding=enc) as f:
content = f.read()
print(f"成功使用{enc}编码读取文件")
break
except UnicodeDecodeError:
continue
else:
print("无法用任何已知编码读取文件")
处理编码的建议:
- 明确知道编码时,直接在open()中指定
- 不确定编码时,可以尝试chardet库自动检测
- 写入文件时也最好明确指定编码
4.2 大文件处理技巧
处理大文件时需要特别注意内存使用:
- 逐行处理(文本文件)
python复制with open('huge.log', 'r') as f:
for line in f:
process(line) # 逐行处理
- 分块读取(二进制文件)
python复制CHUNK_SIZE = 1024 * 1024 # 1MB
with open('large.bin', 'rb') as f:
while True:
chunk = f.read(CHUNK_SIZE)
if not chunk:
break
process(chunk)
- 使用内存映射(mmap)
python复制import mmap
with open('large.data', 'r+b') as f:
with mmap.mmap(f.fileno(), 0) as mm:
# 像操作内存一样操作文件
data = mm[1000:2000] # 读取1000-2000字节
4.3 常见错误与解决方法
- FileNotFoundError
- 问题:文件不存在
- 解决:检查路径是否正确,或先创建文件
- PermissionError
- 问题:没有权限
- 解决:检查文件权限,或使用管理员权限
- UnicodeDecodeError
- 问题:编码不匹配
- 解决:指定正确的编码参数
- IsADirectoryError
- 问题:尝试打开目录
- 解决:检查路径是否指向文件
- 文件被占用无法写入
- 问题:其他程序正在使用文件
- 解决:关闭其他程序,或等待释放
5. 实际应用案例
5.1 日志文件分析
分析服务器日志是文件操作的典型应用:
python复制def analyze_log(log_file):
error_count = 0
with open(log_file, 'r') as f:
for line in f:
if 'ERROR' in line:
error_count += 1
print(f"发现错误: {line.strip()}")
print(f"总共发现 {error_count} 个错误")
analyze_log('server.log')
5.2 配置文件读取
处理JSON格式的配置文件:
python复制import json
def load_config(config_file):
try:
with open(config_file, 'r') as f:
config = json.load(f)
return config
except FileNotFoundError:
print(f"配置文件 {config_file} 不存在")
return {}
except json.JSONDecodeError:
print(f"配置文件 {config_file} 格式错误")
return {}
config = load_config('settings.json')
print(config.get('timeout', 30))
5.3 数据清洗与转换
处理CSV数据文件:
python复制import csv
def clean_data(input_file, output_file):
with open(input_file, 'r') as fin, open(output_file, 'w', newline='') as fout:
reader = csv.reader(fin)
writer = csv.writer(fout)
# 跳过标题行
header = next(reader)
writer.writerow(header)
# 处理数据行
for row in reader:
# 清洗数据:去除空格,转换格式等
cleaned = [cell.strip() for cell in row]
writer.writerow(cleaned)
clean_data('raw_data.csv', 'cleaned_data.csv')
5.4 实现简单的文件加密
使用异或运算实现简单的文件加密:
python复制def xor_crypt(input_file, output_file, key):
with open(input_file, 'rb') as fin, open(output_file, 'wb') as fout:
while True:
chunk = fin.read(1024)
if not chunk:
break
# 对每个字节进行异或运算
encrypted = bytes([b ^ key for b in chunk])
fout.write(encrypted)
# 加密
xor_crypt('secret.txt', 'secret.enc', 0x55)
# 解密(加密和解密是相同的操作)
xor_crypt('secret.enc', 'secret.dec', 0x55)
6. 性能优化与最佳实践
6.1 缓冲策略选择
open()函数的buffering参数控制文件缓冲策略:
- 0:关闭缓冲(仅二进制模式)
- 1:行缓冲(仅文本模式)
-
1:指定缓冲区大小(字节)
- -1:使用默认缓冲区大小(通常为8192字节)
python复制# 使用大缓冲区提高大文件读取性能
with open('bigfile.data', 'rb', buffering=1024*1024) as f:
data = f.read()
6.2 文件操作性能对比
不同文件操作方式的性能差异:
- 小文件(<1MB):
- read()最快
- 方法选择影响不大
- 中等文件(1MB-100MB):
- 逐行迭代比readlines()更省内存
- 适当增大缓冲区有帮助
- 大文件(>100MB):
- 必须使用逐行或分块处理
- mmap可能提供最佳性能
6.3 跨平台兼容性处理
不同操作系统的文件系统差异:
- 路径分隔符:Windows用'',Unix用'/'
- 换行符:Windows用'\r\n',Unix用'\n'
- 文件大小写敏感性
解决方案:
- 使用os.path处理路径
python复制import os
file_path = os.path.join('dir', 'subdir', 'file.txt')
- 使用newline参数控制换行符
python复制with open('file.txt', 'w', newline='') as f:
f.write('line1\nline2\n') # 会按系统默认转换换行符
- 统一使用小写文件名
6.4 文件锁与并发访问
多进程/线程同时访问文件时可能冲突,解决方案:
- 使用fcntl(Unix)或msvcrt(Windows)模块加锁
python复制import fcntl
with open('shared.txt', 'a') as f:
fcntl.flock(f, fcntl.LOCK_EX) # 排他锁
f.write('重要数据\n')
fcntl.flock(f, fcntl.LOCK_UN) # 释放锁
- 使用临时文件+原子重命名
python复制import os
import tempfile
def safe_write(filename, data):
# 先写入临时文件
with tempfile.NamedTemporaryFile('w', dir=os.path.dirname(filename), delete=False) as tf:
tmpname = tf.name
tf.write(data)
# 原子重命名
os.replace(tmpname, filename)
safe_write('important.txt', '关键数据')
7. Python标准库中的文件工具
7.1 os模块文件操作
os模块提供了底层文件系统操作:
python复制import os
# 文件属性
size = os.path.getsize('file.txt')
mtime = os.path.getmtime('file.txt') # 修改时间
# 文件操作
os.rename('old.txt', 'new.txt')
os.remove('file.txt') # 删除文件
os.mkdir('newdir') # 创建目录
# 遍历目录
for entry in os.scandir('mydir'):
if entry.is_file():
print(entry.name, entry.path)
7.2 glob模块文件查找
使用通配符查找文件:
python复制import glob
# 查找所有txt文件
txt_files = glob.glob('*.txt')
print(txt_files)
# 递归查找
all_py_files = glob.glob('**/*.py', recursive=True)
7.3 tempfile模块临时文件
安全创建临时文件和目录:
python复制import tempfile
# 创建临时文件(自动删除)
with tempfile.NamedTemporaryFile('w+t') as tmp:
tmp.write('临时数据')
tmp.seek(0)
print(tmp.read())
# 创建临时目录
with tempfile.TemporaryDirectory() as tmpdir:
print(f"临时目录: {tmpdir}")
# 在目录中工作
7.4 pathlib模块面向对象路径操作
Python3.4+推荐使用pathlib处理文件路径:
python复制from pathlib import Path
# 创建Path对象
p = Path('data/file.txt')
# 常用操作
print(p.exists()) # 是否存在
print(p.is_file()) # 是否是文件
print(p.suffix) # 扩展名
print(p.stem) # 不带扩展名的文件名
# 读写文件
content = p.read_text(encoding='utf-8')
p.write_text('新内容')
# 路径组合
new_p = p.parent / 'newdir' / 'newfile.txt'
8. 第三方库推荐
8.1 处理特殊文件格式
- pandas:专业处理CSV/Excel等表格数据
python复制import pandas as pd
# 读取CSV
df = pd.read_csv('data.csv')
# 处理数据
df = df[df['value'] > 0]
# 写入Excel
df.to_excel('output.xlsx', index=False)
- PyYAML:处理YAML配置文件
python复制import yaml
with open('config.yml') as f:
config = yaml.safe_load(f)
8.2 高级文件系统操作
- watchdog:监控文件系统变化
python复制from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class MyHandler(FileSystemEventHandler):
def on_modified(self, event):
print(f"文件被修改: {event.src_path}")
observer = Observer()
observer.schedule(MyHandler(), path='.', recursive=True)
observer.start()
- shutil:高级文件操作
python复制import shutil
# 复制文件
shutil.copy2('src.txt', 'dst.txt')
# 复制目录
shutil.copytree('src_dir', 'dst_dir')
# 删除目录树
shutil.rmtree('dir_to_remove')
8.3 压缩文件处理
- zipfile:处理ZIP压缩包
python复制import zipfile
# 创建ZIP文件
with zipfile.ZipFile('archive.zip', 'w') as zf:
zf.write('file1.txt')
zf.write('file2.txt')
# 解压ZIP文件
with zipfile.ZipFile('archive.zip', 'r') as zf:
zf.extractall('extracted')
- gzip:处理gzip压缩
python复制import gzip
# 压缩文件
with open('data.txt', 'rb') as fin, gzip.open('data.txt.gz', 'wb') as fout:
fout.write(fin.read())
# 解压文件
with gzip.open('data.txt.gz', 'rb') as fin:
content = fin.read().decode('utf-8')
