Python文件IO与序列化
文件IO(Input/Output)输入(Input):从文件读取数据到程序内存中输出(Output):将程序内存中的数据写入文件序列化:将内存中的数据结构或对象转换为可以存储或传输的格式的过程反序列化:将序列化后的数据重新转换为内存中的对象的过程# 自定义类# 自定义序列化函数return {# 自定义反序列化函数return dct# 使用自定义序列化person = Person("李华",
第一部分:文件操作基础概念
1.1 什么是文件IO?
文件IO(Input/Output) 指的是程序与外部文件之间的数据交换:
-
输入(Input):从文件读取数据到程序内存中
-
输出(Output):将程序内存中的数据写入文件
1.2 为什么需要文件操作?
-
数据持久化:程序运行结束后,数据不会丢失
-
配置存储:保存程序的设置和配置信息
-
数据交换:不同程序之间共享数据
-
日志记录:记录程序运行状态和错误信息
1.3 文件类型
-
文本文件:以字符形式存储,如
.txt,.py,.csv -
二进制文件:以字节形式存储,如
.jpg,.mp3,.exe
第二部分:文件基本操作详解
2.1 文件打开模式详解
# 'r' - 只读模式(默认)
# 文件必须存在,否则会报错
with open('file.txt', 'r') as f:
content = f.read()
# 'w' - 写入模式
# 如果文件存在,会清空内容;如果不存在,会创建新文件
with open('file.txt', 'w') as f:
f.write('Hello World')
# 'a' - 追加模式
# 在文件末尾添加内容,不会清空原有内容
with open('file.txt', 'a') as f:
f.write('\nNew line')
# 'x' - 独占创建模式
# 只能创建新文件,如果文件已存在会报错
try:
with open('new_file.txt', 'x') as f:
f.write('This is a new file')
except FileExistsError:
print("文件已存在!")
# 'b' - 二进制模式
# 用于处理图片、视频等二进制文件
with open('image.jpg', 'rb') as f:
binary_data = f.read()
# '+' - 读写模式
# 可以同时进行读写操作
with open('file.txt', 'r+') as f:
content = f.read() # 先读取
f.write('New data') # 再写入
2.2 文件编码问题
# 指定编码方式(重要!)
# 在Windows系统上尤其需要注意编码问题
# UTF-8编码(推荐)
with open('file.txt', 'r', encoding='utf-8') as f:
content = f.read()
# GBK编码(中文Windows默认)
with open('file.txt', 'r', encoding='gbk') as f:
content = f.read()
# 处理编码错误
try:
with open('file.txt', 'r', encoding='utf-8') as f:
content = f.read()
except UnicodeDecodeError:
print("文件编码不匹配!")
# 尝试其他编码
with open('file.txt', 'r', encoding='gbk') as f:
content = f.read()
第三部分:文件读取方法详解
3.1 各种读取方法对比
# 创建示例文件
with open('sample.txt', 'w', encoding='utf-8') as f:
f.write("""第一行内容
第二行内容
第三行内容
这是文件的最后一行""")
print("=== read() 方法 ===")
# 读取整个文件内容
with open('sample.txt', 'r', encoding='utf-8') as f:
content = f.read()
print(f"整个文件内容:\n{content}")
print(f"内容类型: {type(content)}") # str类型
print("\n=== readline() 方法 ===")
# 逐行读取
with open('sample.txt', 'r', encoding='utf-8') as f:
line1 = f.readline()
line2 = f.readline()
print(f"第一行: {line1.strip()}") # strip() 去除换行符
print(f"第二行: {line2.strip()}")
print("\n=== readlines() 方法 ===")
# 读取所有行,返回列表
with open('sample.txt', 'r', encoding='utf-8') as f:
lines = f.readlines()
print(f"所有行: {lines}")
print(f"行数: {len(lines)}")
print("\n=== 迭代文件对象 ===")
# 最推荐的方式,内存友好
with open('sample.txt', 'r', encoding='utf-8') as f:
for line_num, line in enumerate(f, 1):
print(f"第{line_num}行: {line.strip()}")
3.2 文件指针操作
# 文件指针概念:表示当前读写位置
with open('test.txt', 'w+', encoding='utf-8') as f: # w+ 可读可写
f.write("Hello World\nPython File IO")
# 获取当前指针位置
print(f"写入后指针位置: {f.tell()}")
# 移动指针到文件开头
f.seek(0)
print(f"移动后指针位置: {f.tell()}")
# 读取前5个字符
content = f.read(5)
print(f"前5个字符: {content}")
print(f"读取后指针位置: {f.tell()}")
# 从当前位置继续读取
rest_content = f.read()
print(f"剩余内容: {rest_content}")
第四部分:文件写入方法详解
4.1 各种写入方法
# write() 方法 - 写入字符串
with open('write_demo.txt', 'w', encoding='utf-8') as f:
f.write("这是第一行\n")
f.write("这是第二行\n")
# 注意:write() 不会自动添加换行符
# writelines() 方法 - 写入字符串列表
lines = ["第一行\n", "第二行\n", "第三行\n"]
with open('writelines_demo.txt', 'w', encoding='utf-8') as f:
f.writelines(lines)
# 格式化写入
name = "张三"
age = 25
score = 95.5
with open('format_demo.txt', 'w', encoding='utf-8') as f:
f.write(f"姓名: {name}\n")
f.write(f"年龄: {age}\n")
f.write(f"分数: {score:.1f}\n")
4.2 缓冲区控制
# 文件写入的缓冲区
# 默认情况下,写入操作会先进入缓冲区,不会立即写入磁盘
# 强制刷新缓冲区
with open('buffer_demo.txt', 'w', encoding='utf-8') as f:
f.write("这行内容还在缓冲区中...")
f.flush() # 立即将缓冲区内容写入磁盘
print("数据已刷新到磁盘")
f.write("这是另一行内容")
# 没有调用flush(),可能在缓冲区中
# 禁用缓冲区
with open('no_buffer.txt', 'w', buffering=0, encoding='utf-8') as f:
f.write("这条内容会立即写入磁盘")
第五部分:文件操作高级技巧
5.1 上下文管理器原理
# 理解 with 语句的工作原理
# with 语句实际上调用了文件的 __enter__ 和 __exit__ 方法
# 传统方式(不推荐)
file = None
try:
file = open('traditional.txt', 'w')
file.write("传统方式")
finally:
if file:
file.close()
# 现代方式(推荐)
with open('modern.txt', 'w') as f:
f.write("现代方式")
# 文件会自动关闭,即使发生异常
5.2 文件异常处理
import os
def safe_file_operation(filename, mode='r'):
"""安全的文件操作函数"""
try:
with open(filename, mode, encoding='utf-8') as f:
if 'r' in mode:
return f.read()
elif 'w' in mode or 'a' in mode:
f.write("操作成功")
return True
except FileNotFoundError:
print(f"错误:文件 {filename} 不存在")
except PermissionError:
print(f"错误:没有权限访问文件 {filename}")
except UnicodeDecodeError:
print("错误:文件编码不匹配")
except Exception as e:
print(f"未知错误:{e}")
return None
# 测试异常处理
safe_file_operation('nonexistent.txt') # 文件不存在
第六部分:序列化概念详解
6.1 什么是序列化?
序列化:将内存中的数据结构或对象转换为可以存储或传输的格式的过程 反序列化:将序列化后的数据重新转换为内存中的对象的过程
6.2 为什么需要序列化?
-
数据持久化:保存程序状态
-
网络传输:在不同系统间传递数据
-
进程间通信:在不同进程间共享数据
-
配置文件:保存复杂的配置信息
第七部分:JSON序列化详解
7.1 JSON基本使用
-
键必须用双引号包裹:如
"name": "张三"正确,name: "张三"或'name': "张三"错误; -
字符串值必须用双引号包裹:如
"gender": "男"正确,"gender": '男'错误; -
末尾无多余逗号:对象 / 数组的最后一个元素后不能加逗号,如
{"a":1, "b":2,}错误; -
不支持注释:JSON 语法中没有注释格式(// 或 /* */ 都不允许),如需注释需借助工具或额外字段;
-
不支持函数 /undefined:仅支持上述 6 种数据类型,函数、undefined 会被解析器忽略或报错。
import json
# Python数据类型与JSON对应关系
"""
Python -> JSON
dict object
list, tuple array
str string
int, float number
True true
False false
None null
"""
data = {
"name": "张三",
"age": 25,
"scores": [85, 92, 78],
"is_student": False,
"address": None
}
# 序列化:Python对象 -> JSON字符串
json_string = json.dumps(data, ensure_ascii=False, indent=2)
print("JSON字符串:")
print(json_string)
# 反序列化:JSON字符串 -> Python对象
python_obj = json.loads(json_string)
print("\nPython对象:")
print(python_obj)
print(f"类型: {type(python_obj)}")
7.2 JSON文件操作
import json
# 创建复杂数据
company = {
"name": "科技公司",
"employees": [
{"name": "张三", "department": "技术部", "salary": 15000},
{"name": "李四", "department": "市场部", "salary": 12000},
{"name": "王五", "department": "人事部", "salary": 10000}
],
"founded": "2020-01-01"
}
# 写入JSON文件
with open('company.json', 'w', encoding='utf-8') as f:
json.dump(company, f, ensure_ascii=False, indent=4)
# 读取JSON文件
with open('company.json', 'r', encoding='utf-8') as f:
loaded_company = json.load(f)
print("从文件加载的数据:")
print(json.dumps(loaded_company, ensure_ascii=False, indent=2))
7.3 自定义JSON序列化
import json
from datetime import datetime
# 自定义类
class Person:
def __init__(self, name, birth_date):
self.name = name
self.birth_date = birth_date
# 自定义序列化函数
def person_encoder(obj):
if isinstance(obj, Person):
return {
"name": obj.name,
"birth_date": obj.birth_date.isoformat(),
"age": (datetime.now() - obj.birth_date).days // 365
}
raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
# 自定义反序列化函数
def person_decoder(dct):
if 'birth_date' in dct and 'name' in dct:
return Person(dct['name'], datetime.fromisoformat(dct['birth_date']))
return dct
# 使用自定义序列化
person = Person("李华", datetime(1995, 5, 15))
# 序列化
person_json = json.dumps(person, default=person_encoder, ensure_ascii=False)
print("自定义序列化结果:")
print(person_json)
# 反序列化
person_obj = json.loads(person_json, object_hook=person_decoder)
print(f"\n反序列化对象: {person_obj.name}, 生日: {person_obj.birth_date}")
第八部分:pickle序列化详解
8.1 pickle基本使用
import pickle
# pickle可以序列化几乎所有的Python对象
data = {
"name": "测试数据",
"value": [1, 2, 3, 4, 5],
"tuple_data": (1, 2, 3),
"set_data": {1, 2, 3}
}
# 序列化到文件
with open('data.pkl', 'wb') as f: # 注意:二进制模式
pickle.dump(data, f)
# 从文件反序列化
with open('data.pkl', 'rb') as f: # 注意:二进制模式
loaded_data = pickle.load(f)
print("pickle加载的数据:")
print(loaded_data)
8.2 pickle序列化自定义对象
import pickle
class Student:
def __init__(self, name, grade, subjects):
self.name = name
self.grade = grade
self.subjects = subjects
def display(self):
print(f"学生: {self.name}, 年级: {self.grade}")
print(f"科目: {', '.join(self.subjects)}")
# 创建学生对象
student = Student("王小明", "三年级", ["数学", "语文", "英语"])
# 序列化对象
with open('student.pkl', 'wb') as f:
pickle.dump(student, f)
# 反序列化对象
with open('student.pkl', 'rb') as f:
loaded_student = pickle.load(f)
loaded_student.display()
更多推荐

所有评论(0)