0%

Python3 文件操作:从基础到高级的完整指南

Python 文件操作:读写文件这件事,记住 with open 就够了

写程序,文件操作避不开。读配置、写日志、处理数据、导出报表——天天都在跟文件打交道。

Python 的文件操作其实就一件事:with open() 打开文件,然后读或写。语法很简单,但实际用的时候有些细节——编码、大文件、异常处理——不注意就会出问题。

核心原则:永远用 with open

1
2
3
4
5
6
7
8
9
# 推荐写法
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
# 文件自动关闭,不用手动 close

# 不推荐
f = open("data.txt", "r")
content = f.read()
f.close() # 万一前面报错,close 不会执行

with 语句会在代码块结束后自动关闭文件,即使中间抛异常也一样。记住这一点,就不用操心资源泄露的问题了。

读文件:三种方式,按需取用

1. 小文件:直接读完

1
2
with open("config.json", "r", encoding="utf-8") as f:
content = f.read()

文件不大的时候,这是最直接的写法。几 MB 以内的文件都没问题。

2. 大文件:逐行读,不占内存

1
2
3
4
5
with open("large_log.txt", "r", encoding="utf-8") as f:
for line in f:
# 处理每一行
if "ERROR" in line:
print(line.strip())

for line in f 是逐行读取,不会一次性把所有内容加载到内存。处理几 GB 的日志文件就用这个方式。

3. 读所有行到列表

1
2
3
with open("data.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
# lines 是一个列表,每行一个元素

注意 readlines() 会把所有行都读进内存,适合小文件。大文件还是用上面的逐行遍历。

写文件:覆盖还是追加

1
2
3
4
5
6
7
8
# 覆盖写('w'):文件存在就清空,不存在就创建
with open("output.txt", "w", encoding="utf-8") as f:
f.write("第一行\n")
f.write("第二行\n")

# 追加写('a'):在文件末尾添加
with open("output.txt", "a", encoding="utf-8") as f:
f.write("第三行\n")

写多行:

1
2
3
lines = ["第一行\n", "第二行\n", "第三行\n"]
with open("output.txt", "w", encoding="utf-8") as f:
f.writelines(lines)

writelines() 不会自动加换行,需要自己在字符串里带上 \n

编码:别偷懒,每次都指定 utf-8

1
2
3
4
5
6
7
# 指定编码
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()

# 不指定编码,在不同系统上可能出问题
with open("data.txt", "r") as f:
content = f.read()

Windows 上默认编码可能是 gbk,Linux 上是 utf-8。 不指定编码的话,同样的代码在不同环境表现不一样。每次都写 encoding="utf-8" 是最省事的做法。

如果遇到 UnicodeDecodeError,说明文件编码不是 utf-8,换成其他编码试试:

1
2
3
4
5
6
try:
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
except UnicodeDecodeError:
with open("data.txt", "r", encoding="gbk") as f:
content = f.read()

二进制文件:图片、音频、视频

读二进制文件用 'rb',写用 'wb',不需要指定编码。

1
2
3
4
5
6
7
8
9
# 读图片
with open("image.jpg", "rb") as f:
data = f.read()
print(f"文件大小:{len(data)} 字节")

# 复制文件
with open("source.jpg", "rb") as src:
with open("copy.jpg", "wb") as dst:
dst.write(src.read())

复制大文件不要一次性读完,应该分块读写:

1
2
3
4
5
6
7
8
chunk_size = 8192
with open("source.iso", "rb") as src:
with open("copy.iso", "wb") as dst:
while True:
chunk = src.read(chunk_size)
if not chunk:
break
dst.write(chunk)

文件存在性判断和目录操作

判断文件/目录是否存在:

1
2
3
4
5
6
7
8
9
from pathlib import Path

p = Path("data.txt")

if p.exists():
if p.is_file():
print("是文件")
elif p.is_dir():
print("是目录")

创建目录:

1
2
3
4
5
6
7
from pathlib import Path

# 创建单级目录
Path("data").mkdir(exist_ok=True)

# 创建多级目录
Path("data/2026/logs").mkdir(parents=True, exist_ok=True)

exist_ok=True 的意思是”目录存在也不报错”,省得每次都要先判断。

遍历目录:

1
2
3
4
5
6
7
8
9
from pathlib import Path

# 找所有 .txt 文件
for file in Path(".").glob("*.txt"):
print(file)

# 递归遍历所有子目录
for file in Path(".").rglob("*.log"):
print(file)

os 模块的老写法也常见:

1
2
3
4
5
6
import os

os.path.exists("data.txt")
os.path.isdir("data")
os.makedirs("data/logs", exist_ok=True)
os.listdir(".")

pathlib 是更新的写法,更直观;os 是老写法,老代码里常见。两种都认识就行,新代码推荐用 pathlib

CSV 文件:用 csv 模块,别自己 split

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import csv

# 读 CSV
with open("data.csv", "r", encoding="utf-8", newline="") as f:
reader = csv.reader(f)
header = next(reader) # 表头
for row in reader:
print(row) # row 是列表

# 写 CSV
rows = [
["姓名", "年龄", "城市"],
["张三", 25, "北京"],
["李四", 30, "上海"],
]
with open("output.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerows(rows)

newline="" 是为了避免 Windows 上出现多余的空行,写 CSV 的时候加上就对了

JSON 文件:用 json 模块

1
2
3
4
5
6
7
8
9
10
import json

# 读 JSON
with open("config.json", "r", encoding="utf-8") as f:
config = json.load(f)

# 写 JSON
data = {"name": "张三", "age": 25}
with open("output.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)

ensure_ascii=False 保留中文,indent=2 让输出可读。这两个参数记不住的话,直接复制用就行。

异常处理:文件操作容易出错的地方

文件操作常见的异常就那么几种,处理好了程序就不会崩:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pathlib import Path

file_path = Path("data.txt")

try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
except FileNotFoundError:
print(f"文件不存在:{file_path}")
except PermissionError:
print(f"没有读取权限:{file_path}")
except UnicodeDecodeError:
print(f"编码错误:{file_path}")
except Exception as e:
print(f"其他错误:{e}")

实际写代码的时候,至少把 FileNotFoundError 处理了,不然用户看到的就是一屏幕红字堆栈。

临时文件:用完自动删

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import tempfile
from pathlib import Path

# 临时文件
with tempfile.NamedTemporaryFile(mode="w+", encoding="utf-8", delete=False) as f:
f.write("临时数据")
f.seek(0)
print(f.read())

# 临时目录
with tempfile.TemporaryDirectory() as temp_dir:
temp_file = Path(temp_dir) / "temp.txt"
temp_file.write_text("临时文件")
# 退出 with 块后自动删除

适合测试场景或者需要暂存中间数据的场景。

欢迎关注我的其它发布渠道