Python的文件操作是日常脚本开发中最常见的需求之一,无论读取配置、处理日志、导出数据还是实现本地持久化,都离不开文件读写。本文从基础API到高级用法,结合实际案例梳理Python文件操作的核心知识点。
- import os, json, csv, shutil, tempfile, chardet
复制代码
一、打开文件的两种模式
内置函数open()是文件操作的入口,语法:open(file, mode='r', encoding=None, buffering=-1)。
常见mode参数:
- 'r':只读,文件必须存在(默认)。
- 'w':覆盖写入,不存在则创建。
- 'a':追加写入,不存在则创建。
- 'x':独占创建,文件已存在则抛异常FileExistsError。
- 'r+'/'w+'/'a+':读写组合,其中r+不截断文件,w+会截断,a+追加且可读。
- 'b':二进制模式,需与r/w/a组合(如'rb')。
- 't':文本模式(默认)。
推荐始终指定encoding='utf-8',避免跨平台乱码。
- # 示例:不同模式的with写法
- with open('config.ini', 'r', encoding='utf-8') as f:
- content = f.read()
- with open('output.txt', 'w', encoding='utf-8') as f:
- f.write('新内容\n')
- with open('app.log', 'a', encoding='utf-8') as f:
- f.write('2026-06-26: 启动\n')
- with open('image.jpg', 'rb') as f:
- data = f.read()
复制代码
二、文件读取的四种方式
1. read(size):一次性读取全部(指定字节数),适合小文件。
2. readline():读取一行,适合逐行处理且需保留行号场景。
3. readlines():返回列表,每行为一个元素,大文件慎用。
4. 直接迭代file object:最内存友好,逐行读取,占用恒定内存,推荐用于大日志文件。
- with open('server.log', 'r', encoding='utf-8') as f:
- for line in f:
- if 'ERROR' in line:
- error_count += 1
复制代码
三、写入方法
- write(str):写入字符串,需手动添加换行符'\n'。
- writelines(iterable):写入多个字符串,不会自动换行,元素需自带换行符。
- lines = ['苹果\n', '香蕉\n', '橙子\n']
- with open('fruits.txt', 'w', encoding='utf-8') as f:
- f.writelines(lines)
复制代码
四、with语句与上下文管理器
传统open+close存在忘记关闭或异常时未释放资源的风险。with语句通过上下文管理器自动调用__exit__,确保文件被正确关闭,即使发生异常。
同时打开多个文件:- with open('src.txt', 'r', encoding='utf-8') as src, \
- open('dst.txt', 'w', encoding='utf-8') as dst:
- dst.write(src.read())
复制代码
五、文件指针控制:seek()与tell()
- tell():返回当前指针位置(字节数)。
- seek(offset, whence):移动指针。whence=0(开头,默认)、1(当前位置)、2(末尾)。注意:文本模式下只允许从开头定位,二进制模式可自由移动。
实战:读取文件头部和尾部。- with open('large.dat', 'rb') as f:
- first_10 = f.read(10)
- f.seek(-10, 2) # 从末尾往回10字节
- last_10 = f.read(10)
复制代码
六、异常处理
常见异常:FileNotFoundError、PermissionError、IOError。建议用try-except包裹文件操作,尤其是读取外部文件时。
- try:
- with open('config.txt', 'r', encoding='utf-8') as f:
- content = f.read()
- except FileNotFoundError:
- print('文件不存在')
- except PermissionError:
- print('无权限')
- except IOError as e:
- print(f'I/O错误:{e}')
复制代码
七、编码处理
Python 3默认编码UTF-8,但实际环境可能遇到GBK等。指定encoding即可,错误处理可用errors='ignore'或'replace'。
自动检测编码推荐chardet库:- import chardet
- with open('unknown.txt', 'rb') as f:
- raw = f.read()
- result = chardet.detect(raw)
- encoding = result['encoding']
- with open('unknown.txt', 'r', encoding=encoding) as f:
- content = f.read()
复制代码
八、二进制文件与大文件分块复制
二进制模式用于图片、视频等非文本文件。大文件应分块读写避免内存溢出:- chunk_size = 4096
- with open('source.mp4', 'rb') as src, open('copy.mp4', 'wb') as dst:
- while True:
- chunk = src.read(chunk_size)
- if not chunk:
- break
- dst.write(chunk)
复制代码
九、os与shutil模块
os模块负责文件/目录操作:
- os.getcwd()、os.listdir()、os.rename()、os.remove()、os.path.exists()等。
- os.mkdir()创建单级目录,os.makedirs()创建多级目录。
- os.path.join()跨平台拼接路径,os.path.basename()/dirname(),os.path.splitext()分离扩展名。
shutil提供高级操作:
- shutil.copy()/copy2()复制文件(copy2保留元数据)。
- shutil.copytree()递归复制目录。
- shutil.move()移动文件/目录。
- shutil.rmtree()删除非空目录树(谨慎)。
十、CSV读写
内置csv模块:- import csv
- # 写入
- with open('people.csv', 'w', newline='', encoding='utf-8') as f:
- writer = csv.writer(f)
- writer.writerows([['姓名', '年龄'], ['张三', 25]])
- # 读取
- with open('people.csv', 'r', encoding='utf-8') as f:
- reader = csv.reader(f)
- for row in reader:
- print(row)
复制代码 DictWriter/DictReader可直接操作字典:- with open('people_dict.csv', 'w', newline='', encoding='utf-8') as f:
- fieldnames = ['name', 'age']
- writer = csv.DictWriter(f, fieldnames=fieldnames)
- writer.writeheader()
- writer.writerows([{'name':'张三','age':25}, {'name':'李四','age':30}])
复制代码
十一、JSON读写
json模块对接字典/列表:- import json
- data = {'name': '张三', 'age': 25, 'hobbies': ['阅读', '编程']}
- with open('data.json', 'w', encoding='utf-8') as f:
- json.dump(data, f, ensure_ascii=False, indent=4)
- with open('data.json', 'r', encoding='utf-8') as f:
- loaded = json.load(f)
复制代码 字符串互转用json.dumps()/json.loads()。
十二、临时文件与目录
tempfile模块:- import tempfile
- with tempfile.TemporaryFile(mode='w+t') as tf:
- tf.write('临时数据')
- tf.seek(0)
- print(tf.read())
- # 离开with自动删除
复制代码 NamedTemporaryFile可保留文件名,TemporaryDirectory创建临时目录。
十三、综合实战案例
案例1:日志分析器- def analyze_log(log_file, error_output):
- error_lines = []
- try:
- with open(log_file, 'r', encoding='utf-8') as f:
- for line in f:
- if 'ERROR' in line.upper():
- error_lines.append(line.strip())
- with open(error_output, 'w', encoding='utf-8') as f:
- f.write(f'共发现 {len(error_lines)} 个错误:\n')
- f.writelines([line + '\n' for line in error_lines])
- print(f'分析完成,结果保存至{error_output}')
- except FileNotFoundError:
- print('日志文件不存在')
- except PermissionError:
- print('无权限读取')
复制代码
案例2:学生成绩管理系统(JSON持久化)- import json, os
- class StudentManager:
- def __init__(self, data_file='students.json'):
- self.data_file = data_file
- self.students = []
- self.load_data()
- def load_data(self):
- if os.path.exists(self.data_file):
- with open(self.data_file, 'r', encoding='utf-8') as f:
- self.students = json.load(f)
- else:
- self.students = []
- def save_data(self):
- with open(self.data_file, 'w', encoding='utf-8') as f:
- json.dump(self.students, f, ensure_ascii=False, indent=2)
复制代码
案例3:文件批量重命名- import os
- def batch_rename(dir_path, prefix='file', ext='.txt'):
- for i, fname in enumerate(os.listdir(dir_path)):
- src = os.path.join(dir_path, fname)
- if os.path.isfile(src):
- dst = os.path.join(dir_path, f'{prefix}_{i}{ext}')
- os.rename(src, dst)
复制代码
总结
文件操作核心三要素:打开、读写、关闭。务必使用with语句,指定编码,处理异常。根据文件大小选择合适的读取方式,二进制文件分块操作,熟悉os/shutil进行路径和目录管理。掌握CSV/JSON序列化后即可应对大部分数据持久化场景。 |