【Python系列课程】Python文件操作:从路径处理到with语句
·
📊 阅读时长:20分钟 | 关键词:Python文件操作、open()、读写模式、with语句、os模块、路径处理
引言:和计算机关打交道的唯一方式
前面讲的都是"计算"——加减乘除、列表操作、函数调用。但程序真正强大之处,在于能和文件系统打交道:
- 读取配置文件(
.ini、.json、.yaml) - 处理用户上传的文件(
.csv、.xlsx、图片) - 生成报表输出到本地(
.txt、.pdf、.docx) - 日志系统(
.log文件的读写)
Python 的文件操作 API 设计得非常优雅,学完这篇,你基本上能应付 90% 的文件处理任务。
一、路径操作:文件在哪?
在操作文件之前,你得先搞清楚文件在哪——这就是路径做的事。
1.1 绝对路径 vs 相对路径
| 类型 | 说明 | 示例(Windows) | 示例(macOS/Linux) |
|---|---|---|---|
| 绝对路径 | 从根目录开始的完整路径 | D:\PythonFiles\p01.py |
/home/user/code/main.py |
| 相对路径 | 相对于当前工作目录的路径 | .\data\input.txt |
./data/input.txt |
获取当前工作目录:
import os
cwd = os.getcwd()
print(cwd) # 输出当前工作目录
相对路径的特殊符号:
.→ 当前目录..→ 上一级目录
os.getcwd() # D:\PythonFiles
os.path.join('.', 'data', 'input.txt') # .\data\input.txt
os.path.join('..', 'main.py') # ..\main.py
1.2 os.path 常用方法速查
import os
path = r'D:\PythonFiles\data\input.txt'
os.path.basename(path) # 'input.txt' → 最后一级(文件名)
os.path.dirname(path) # 'D:\PythonFiles\data' → 目录部分
os.path.split(path) # ('D:\...\data', 'input.txt')
os.path.splitext(path) # ('D:\...\input', '.txt') → 拆分扩展名
os.path.exists(path) # False(不存在)
os.path.isfile(path) # False
os.path.isdir(path) # False

1.3 os.path.join():智能拼接路径(跨平台必备)
永远不要用字符串拼接路径! 不同操作系统的路径分隔符不同(Windows 用 \,macOS/Linux 用 /)。os.path.join() 会根据当前操作系统自动选择正确的分隔符。
import os
# ❌ 错误写法(不跨平台)
path = 'data' + '\\' + 'input.txt' # 在 Mac 上会出错
# ✅ 正确写法
path = os.path.join('data', 'input.txt')
print(path)
# Windows → data\input.txt
# macOS/Linux → data/input.txt
1.4 创建目录:os.makedirs()
import os
# 创建单层目录
os.mkdir('new_folder')
# 递归创建多层目录(自动创建中间目录)
os.makedirs('./dir1/dir2/dir3', exist_ok=True)
# exist_ok=True:目录已存在时不报错
二、open():打开文件的万能钥匙
2.1 基本语法
file = open(file, mode='r', encoding=None)
| 参数 | 说明 |
|---|---|
file |
文件路径(绝对或相对) |
mode |
打开模式,默认 'r'(只读) |
encoding |
文本文件编码,建议显式指定 'utf-8' |
返回一个文件对象(迭代器对象),可以用 for 循环逐行读取。
2.2 文件打开模式详解
| 模式 | 说明 | 文件不存在时 | 文件已存在时 |
|---|---|---|---|
'r' |
只读 | 报错 FileNotFoundError |
正常打开,指针在开头 |
'w' |
只写(覆盖) | 创建新文件 | 清空原内容再写入 |
'a' |
只写(追加) | 创建新文件 | 指针在末尾,追加写入 |
'x' |
独占创建 | 创建新文件 | 报错 FileExistsError |
'b' |
二进制模式 | — | 需配合 r/w/a 使用 |
'+' |
读写模式 | — | 需配合 r/w/a 使用 |
组合模式示例:
open('file.txt', 'rb') # 二进制只读(如读取图片)
open('file.txt', 'wb') # 二进制只写
open('file.txt', 'r+') # 读写,指针在开头
open('file.txt', 'w+') # 读写,清空后写入
open('file.txt', 'a+') # 读写,指针在末尾
2.3 文本文件 vs 二进制文件
| 类型 | 编码 | 示例文件 | 打开模式 |
|---|---|---|---|
| 文本文件 | 需要指定 encoding |
.txt、.py、.json、.md |
'r'/'w'/'a'(默认) |
| 二进制文件 | 无编码,直接读写字节 | .png、.mp3、.exe、.zip |
'rb'/'wb'/'ab' |
三、文件对象的常用方法
3.1 读取内容
with open('./exam.txt', 'r', encoding='utf-8') as f:
# 方式1:next() 读取一行(文件是迭代器)
print(next(f))
# 方式2:for 循环逐行读取(最常用,内存友好)
for line in f:
print(line, end='') # end='' 去掉多余的换行
# 方式3:read(size) 读取指定字符数
f.seek(0) # 指针回到开头
content = f.read(5) # 读取前5个字符
print(content)
# 方式4:read() 读取全部
f.seek(0)
all_content = f.read()
print(all_content)
# 方式5:readlines() 读取全部行到列表
f.seek(0)
lines = f.readlines()
print(lines) # ['line1\n', 'line2\n', ...]

3.2 写入内容
with open('./exam.txt', 'w', encoding='utf-8') as f:
# write(s):写入字符串,返回写入的字符数
num = f.write('Hello World\n')
print(f'写入了 {num} 个字符')
# writelines(lines):写入字符串列表(不会自动加换行!)
lines = ['Line 1\n', 'Line 2\n', 'Line 3\n']
f.writelines(lines)
⚠️ 注意:writelines() 不会自动添加换行符,需要自己加 \n。
3.3 移动文件指针:seek(offset)
with open('./exam.txt', 'r+', encoding='utf-8') as f:
f.write('Hello')
f.seek(0) # 指针回到开头
print(f.read()) # 从头开始读取
3.4 刷新缓冲区:flush()
写入文件时,Python 会先把内容放到缓冲区,等缓冲区满了或文件关闭时才真正写入磁盘。flush() 可以强制立即写入。
import time
f = open('./test.txt', 'a', encoding='utf-8')
f.write('123456789\n')
f.flush() # 立即写入磁盘(不等文件关闭)
time.sleep(5) # 这5秒内文件里已经有内容了
f.close()
四、with 语句:最优雅的文件操作方式
4.1 为什么要用 with?
传统写法需要手动关闭文件,如果中间发生异常,close() 可能执行不到:
# ❌ 不推荐的写法
f = open('./test.txt', 'w', encoding='utf-8')
f.write('hello world')
# 如果这里发生异常,close() 不会执行 → 文件损坏风险
f.close()
with 语句的好处:无论是否发生异常,退出 with 块时自动执行 close()。
# ✅ 推荐写法
with open('./test.txt', 'w', encoding='utf-8') as f:
f.write('hello world')
# 退出 with 块时,自动调用 f.close()
等价于:
f = open('./test.txt', 'w', encoding='utf-8')
try:
f.write('hello world')
finally:
f.close() # 无论如何都会执行
4.2 with + try/except/finally 组合
try:
with open('./test.txt', 'r', encoding='utf-8') as f:
content = f.read()
print(content)
except FileNotFoundError:
print('文件不存在!')
except UnicodeDecodeError:
print('文件编码不是 UTF-8!')
finally:
print('文件操作结束(自动关闭)')
五、实战:几个常用文件操作场景
5.1 复制文件
def copy_file(src, dst):
"""复制文件(支持文本和二进制)"""
with open(src, 'rb') as fsrc:
with open(dst, 'wb') as fdst:
while True:
chunk = fsrc.read(4096) # 每次读 4KB
if not chunk:
break
fdst.write(chunk)
print(f'已复制:{src} → {dst}')
copy_file('./source.jpg', './backup/copy.jpg')
5.2 逐行处理日志文件(内存友好)
# 处理大文件时,绝对不能用 read() 一次性读入内存!
# 用 for 循环逐行读取,每次只占用一行的内存
error_count = 0
with open('./app.log', 'r', encoding='utf-8') as f:
for line in f: # 逐行迭代,内存占用极低
if 'ERROR' in line:
error_count += 1
print(f'发现错误:{line.strip()}')
print(f'共发现 {error_count} 处错误')
5.3 CSV 文件读写(数据分析必备)
import csv
# 读取 CSV
with open('./data.csv', 'r', encoding='utf-8') as f:
reader = csv.reader(f)
header = next(reader) # 跳过表头
print(f'表头:{header}')
for row in reader:
print(row)
# 写入 CSV
with open('./output.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['姓名', '年龄', '城市']) # 写表头
writer.writerows([
['小明', 25, '北京'],
['小红', 23, '上海'],
])
六、动手练习
练习 1:统计文件行数
def count_lines(filepath):
"""统计文件行数"""
with open(filepath, 'r', encoding='utf-8') as f:
return sum(1 for _ in f) # 逐行迭代计数
print(count_lines('./exam.txt'))
练习 2:查找包含关键词的行
def grep(filepath, keyword):
"""查找包含关键词的所有行"""
with open(filepath, 'r', encoding='utf-8') as f:
for i, line in enumerate(f, 1):
if keyword in line:
print(f'第 {i} 行:{line.strip()}')
grep('./app.log', 'ERROR')
练习 3:批量重命名文件
import os
def batch_rename(folder, old_ext, new_ext):
"""批量修改文件扩展名"""
for filename in os.listdir(folder):
if filename.endswith(old_ext):
old_path = os.path.join(folder, filename)
new_filename = filename.replace(old_ext, new_ext)
new_path = os.path.join(folder, new_filename)
os.rename(old_path, new_path)
print(f'{filename} → {new_filename}')
batch_rename('./images', '.jpeg', '.jpg')
小结
| 知识点 | 一句话总结 |
|---|---|
| 路径操作 | 用 os.path.join() 拼接路径,跨平台 |
open() |
打开文件,返回文件对象;指定 mode 和 encoding |
| 读写模式 | 'r' 只读 / 'w' 覆盖 / 'a' 追加 / 'b' 二进制 |
| 读取方法 | read() 全读 / readline() 读一行 / for line in f 逐行(推荐) |
| 写入方法 | write() 写字符串 / writelines() 写列表 |
with 语句 |
自动关闭文件,异常处理更安全,必须用 |
| 大文件处理 | 用 for line in f 逐行读取,不要用 read() |

本文是「Python从入门到数据分析」系列的第 13 篇,共 24 篇。关注我,不错过后续更新。
更多推荐

所有评论(0)