IO编程 (Input/Output)
IO编程是指输入/输出操作,包括文件读写、网络通信、控制台交互等。本章重点学习Python中的文件操作和数据序列化。
文件操作基础
┌─────────────────────────────────────────────────────────────────┐
│ 文件操作流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 打开文件 ──→ 读取/写入 ──→ 关闭文件 │
│ │
│ 【传统方式】 │
│ f = open("file.txt", "r") # 打开 │
│ data = f.read() # 读取 │
│ f.close() # 关闭(容易忘记!) │
│ │
│ 【推荐方式 - with 语句】 │
│ with open("file.txt", "r") as f: # 打开,自动管理 │
│ data = f.read() # 读取 │
│ # f 自动关闭 # 离开 with 块自动关闭 │
│ │
└─────────────────────────────────────────────────────────────────┘
文件打开模式
| 模式 | 说明 | 文件不存在 | 原有内容 |
|---|---|---|---|
r |
只读 | 报错 | 保留 |
w |
写入 | 创建 | 清空 |
a |
追加 | 创建 | 保留,在末尾追加 |
x |
新建 | 创建 | 文件存在则报错 |
r+ |
读写 | 报错 | 保留 |
w+ |
读写 | 创建 | 清空 |
a+ |
读写 | 创建 | 保留,末尾追加 |
读取文件
Python
# 读取整个文件内容
with open("test.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
# 读取固定字节数
with open("test.txt", "r") as f:
chunk = f.read(100) # 读取前100个字符
# 逐行读取
with open("test.txt", "r") as f:
for line in f:
print(line.rstrip()) # rstrip() 去除换行符
# 读取所有行到列表
with open("test.txt", "r") as f:
lines = f.readlines()
# 读取到列表(更简洁)
with open("test.txt", "r") as f:
lines = list(f)
# readline() 逐行读取
with open("test.txt", "r") as f:
line1 = f.readline()
line2 = f.readline()
写入文件
Python
# 写入文件(覆盖)
with open("output.txt", "w", encoding="utf-8") as f:
f.write("Hello, World!\n")
f.write("第二行")
# 追加模式
with open("output.txt", "a") as f:
f.write("\n追加的内容")
# 写入多行
lines = ["第一行\n", "第二行\n", "第三行\n"]
with open("output.txt", "w") as f:
f.writelines(lines)
# 使用 join 写入多行(推荐)
lines = ["第一行", "第二行", "第三行"]
with open("output.txt", "w") as f:
f.write("\n".join(lines))
# 写入字节串
with open("binary.bin", "wb") as f:
f.write(b"Hello Bytes")
StringIO 和 BytesIO
在内存中模拟文件操作,适用于不需要真正读写磁盘的场景。
┌─────────────────────────────────────────────────────────────────┐
│ 内存文件 vs 真实文件 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 真实文件: │
│ 程序 ←→ 磁盘文件 │
│ │
│ StringIO / BytesIO: │
│ 程序 ←→ 内存缓冲区 │
│ ↑ │
│ 更快,不需要IO操作 │
│ 常用于测试 │
│ │
└─────────────────────────────────────────────────────────────────┘
Python
from io import StringIO, BytesIO
# StringIO - 操作字符串
buffer = StringIO()
buffer.write("Hello ")
buffer.write("World!")
print(buffer.getvalue()) # Hello World!
# 从字符串创建 StringIO
source = StringIO("初始内容\n第二行")
print(source.readline())
# BytesIO - 操作字节
byte_buffer = BytesIO()
byte_buffer.write(b"Hello")
byte_buffer.write(b" Bytes")
print(byte_buffer.getvalue()) # b'Hello Bytes'
# 实际应用:格式化输出
from io import StringIO
def format_output(items):
buffer = StringIO()
for i, item in enumerate(items, 1):
buffer.write(f"{i}. {item}\n")
return buffer.getvalue()
print(format_output(["苹果", "香蕉", "橙子"]))
JSON 序列化
JSON是跨语言的数据交换格式,Python的 json 模块支持JSON与字典的相互转换。
┌─────────────────────────────────────────────────────────────────┐
│ JSON vs Python 数据类型 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Python JSON │
│ ──────────────────────────────────────── │
│ dict object {"name": "张三"} │
│ list array [1, 2, 3] │
│ str string "hello" │
│ int number 42 │
│ float number 3.14 │
│ True true │
│ False false │
│ None null │
│ │
└─────────────────────────────────────────────────────────────────┘
Python
import json
# Python 对象 → JSON 字符串
data = {
"name": "张三",
"age": 25,
"scores": [90, 85, 92],
"is_student": True,
"address": None
}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
# JSON 字符串 → Python 对象
parsed = json.loads(json_str)
print(parsed["name"])
# 写入 JSON 文件
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 读取 JSON 文件
with open("data.json", "r", encoding="utf-8") as f:
loaded_data = json.load(f)
print(loaded_data)
JSON 处理自定义对象
Python
import json
from datetime import datetime
# 自定义日期编码器
class DateEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
# 使用
data = {
"event": "发布会",
"time": datetime.now()
}
json_str = json.dumps(data, cls=DateEncoder, ensure_ascii=False)
print(json_str)
pickle 序列化
pickle 是Python特有的二进制序列化格式,可以序列化任何Python对象,但只能被Python读取。
Python
import pickle
# 序列化对象
data = {"name": "张三", "scores": [90, 85, 92]}
serialized = pickle.dumps(data)
print(type(serialized)) # <class 'bytes'>
# 反序列化
deserialized = pickle.loads(serialized)
print(deserialized)
# 写入文件
with open("data.pkl", "wb") as f:
pickle.dump(data, f)
# 读取文件
with open("data.pkl", "rb") as f:
loaded = pickle.load(f)
pickle 安全警告
不要从不信任的来源加载 pickle 数据!pickle 可以执行任意代码,攻击者可能利用它植入恶意代码。
不要从不信任的来源加载 pickle 数据!pickle 可以执行任意代码,攻击者可能利用它植入恶意代码。
CSV 文件处理
CSV(逗号分隔值)是常用的表格数据格式。
Python
import csv
# 写入 CSV
with open("users.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["姓名", "年龄", "城市"])
writer.writerow(["张三", 25, "北京"])
writer.writerow(["李四", 30, "上海"])
# 读取 CSV
with open("users.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader:
print(row)
# 使用字典方式读写
with open("users.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(f"姓名: {row['姓名']}, 年龄: {row['年龄']}")
# 写入字典 CSV
with open("users_dict.csv", "w", newline="", encoding="utf-8") as f:
fieldnames = ["姓名", "年龄", "城市"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({"姓名": "王五", "年龄": 28, "城市": "广州"})
知识测验
问题1:以下哪种方式可以正确打开文件并自动关闭?
问题2:pickle 和 JSON 的主要区别是什么?
课后练习
练习1:文件备份工具
实现一个文件备份工具:
- 读取源文件内容
- 写入备份文件(文件名加 .bak 后缀)
- 使用 with 语句确保正确关闭
- 处理文件不存在的情况
练习2:JSON 配置文件管理
实现配置文件的读写:
- 创建一个配置字典(包含数据库配置、应用设置等)
- 使用 JSON 写入文件
- 实现读取并验证配置完整性
- 添加异常处理
练习3:CSV 数据分析
实现CSV数据处理:
- 创建包含学生成绩的CSV文件
- 读取并计算每个学生的平均分
- 找出最高分和最低分
- 按平均分排序输出
🐍 Python 在线代码编辑器
📝 运行结果