第23课 - 读写常见格式文件(CSV, JSON)
学习目标
通过本课学习,你将能够:
- 使用
csv模块读取和写入CSV文件 - 使用
json模块解析和生成JSON格式数据 - 处理CSV文件中的特殊字符和分隔符
- 在Python数据结构与JSON格式之间进行相互转换
- 应用正确的异常处理处理文件格式错误
核心概念
CSV文件:表格数据的通用语言
CSV(逗号分隔值)是一种简单的文本格式,用于存储表格数据。每一行代表一条记录,字段之间通常用逗号分隔。
想象一下Excel表格:每一行是CSV文件的一行,每一列是用逗号分隔的字段。CSV文件的优点是简单、通用,几乎所有电子表格和数据库都能读取它。
JSON文件:结构化数据的现代格式
JSON(JavaScript对象表示法)是一种轻量级的数据交换格式。它以键值对的形式组织数据,比XML更简洁易读。
你可以把JSON看作是Python字典的文本表示。它特别适合存储配置信息、API响应数据等具有层次结构的信息。
代码示例
1. CSV文件读写
import csv
# 写入CSV文件
def write_csv(filename, data):
"""
将数据写入CSV文件
:param filename: 文件名
:param data: 二维列表,第一行为标题行
"""
with open(filename, 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerows(data) # 写入多行数据
# 读取CSV文件
def read_csv(filename):
"""
读取CSV文件并返回数据列表
:param filename: 文件名
:return: 二维列表
"""
data = []
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
data.append(row)
return data
# 使用示例
scores_data = [
['姓名', '语文', '数学', '英语'],
['张三', 85, 90, 78],
['李四', 92, 88, 95],
['王五', 78, 85, 92]
]
write_csv('student_scores.csv', scores_data)
print("CSV文件已写入")
read_data = read_csv('student_scores.csv')
print("读取到的数据:")
for row in read_data:
print(row)
# 使用字典方式读写CSV(更适合有标题的数据)
def write_csv_with_dicts(filename, fieldnames, data):
with open(filename, 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader() # 写入标题行
writer.writerows(data)
def read_csv_as_dicts(filename):
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
return list(reader)
# 字典方式使用示例
student_records = [
{'姓名': '赵六', '语文': 88, '数学': 92, '英语': 85},
{'姓名': '钱七', '语文': 95, '数学': 89, '英语': 91}
]
fieldnames = ['姓名', '语文', '数学', '英语']
write_csv_with_dicts('student_records.csv', fieldnames, student_records)
records = read_csv_as_dicts('student_records.csv')
print("\n字典格式的记录:")
for record in records:
print(f"{record['姓名']}:语文{record['语文']}, 数学{record['数学']}")
2. JSON文件读写
import json
# 写入JSON文件
def write_json(filename, data, indent=4):
"""
将Python数据结构写入JSON文件
:param filename: 文件名
:param data: Python字典或列表
:param indent: 缩进空格数
"""
with open(filename, 'w', encoding='utf-8') as file:
json.dump(data, file, indent=indent, ensure_ascii=False)
# ensure_ascii=False 确保中文正常显示
# 读取JSON文件
def read_json(filename):
"""
读取JSON文件并返回Python数据结构
:param filename: 文件名
:return: 字典或列表
"""
with open(filename, 'r', encoding='utf-8') as file:
return json.load(file)
# JSON字符串转换
def json_to_python(json_string):
"""将JSON字符串转换为Python对象"""
return json.loads(json_string)
def python_to_json(python_object, indent=4):
"""将Python对象转换为JSON字符串"""
return json.dumps(python_object, indent=indent, ensure_ascii=False)
# 使用示例
config_data = {
"database": {
"host": "localhost",
"port": 3306,
"username": "admin",
"password": "secret123",
"databases": ["users", "products", "orders"]
},
"api_keys": {
"google_maps": "AIzaSyD...",
"weather_api": "abc123..."
},
"settings": {
"debug_mode": False,
"max_connections": 100,
"cache_enabled": True
}
}
# 写入JSON配置文件
write_json('config.json', config_data)
print("配置文件已写入:config.json")
# 读取JSON配置文件
loaded_config = read_json('config.json')
print("\n读取的配置信息:")
print(f"数据库主机:{loaded_config['database']['host']}")
print(f"数据库端口:{loaded_config['database']['port']}")
print(f"可用数据库:{', '.join(loaded_config['database']['databases'])}")
# JSON字符串示例
json_string = '''
{
"employees": [
{"name": "John", "age": 30, "department": "技术部"},
{"name": "Anna", "age": 25, "department": "市场部"},
{"name": "Mike", "age": 35, "department": "人事部"}
]
}
'''
# 字符串转换
python_data = json_to_python(json_string)
print("\n从JSON字符串解析的员工数据:")
for emp in python_data['employees']:
print(f"{emp['name']}, {emp['age']}岁, {emp['department']}")
# Python对象转JSON字符串
employees = [
{"name": "Alice", "age": 28, "skills": ["Python", "SQL"]},
{"name": "Bob", "age": 32, "skills": ["Java", "C++", "JavaScript"]}
]
json_output = python_to_json(employees, indent=2)
print("\n生成的JSON字符串:")
print(json_output)
实践练习
练习1:CSV数据处理
要求:创建一个程序,完成以下任务:
- 读取
products.csv文件(假设文件存在,包含产品名称、价格、库存量三列) - 找出所有价格低于50元且库存大于10的产品
- 将筛选后的产品信息写入
cheap_products.csv
预期输出示例:
找到3个符合条件的产品,已保存到cheap_products.csv
练习2:JSON配置管理
要求:编写一个简单的配置管理系统:
- 创建一个JSON文件存储服务器配置
- 提供函数来读取、修改和保存配置
- 支持添加新的配置项
提示:可以创建一个ServerConfig类来封装这些操作
练习3:格式转换器
要求:实现CSV到JSON的转换器:
- 读取一个CSV文件
- 将每一行转换为JSON对象(使用标题行作为键名)
- 将所有行数据作为JSON数组写入新文件
示例转换:
姓名,年龄,城市
张三,25,北京
李四,30,上海
→
[
{"姓名": "张三", "年龄": "25", "城市": "北京"},
{"姓名": "李四", "年龄": "30", "城市": "上海"}
]
常见错误
1. CSV文件编码问题
# 错误:没有指定编码,中文可能出现乱码
with open('data.csv', 'r') as file: # ❌ 可能出现编码问题
data = csv.reader(file)
# 正确:明确指定编码格式
with open('data.csv', 'r', encoding='utf-8') as file: # ✅
data = csv.reader(file)
2. CSV换行符问题
# 错误:Windows下可能出现多余空行
with open('output.csv', 'w') as file: # ❌ Windows会有空行
writer = csv.writer(file)
writer.writerow(['a', 'b', 'c'])
# 正确:使用newline=''参数
with open('output.csv', 'w', newline='') as file: # ✅
writer = csv.writer(file)
writer.writerow(['a', 'b', 'c'])
3. JSON数据类型转换
# 错误:JSON不支持Python特有类型
data = {
"date": datetime.datetime.now(), # ❌ datetime不能直接序列化
"set": {1, 2, 3} # ❌ 集合不能序列化
}
json.dumps(data) # 会抛出TypeError
# 正确:先转换为JSON支持的类型
data = {
"date": datetime.datetime.now().isoformat(), # ✅ 转为字符串
"set": list({1, 2, 3}) # ✅ 转为列表
}
4. 文件路径和权限问题
# 错误:忽略文件路径问题
# 在不同操作系统上路径分隔符不同
data = json.load('/tmp/config.json') # ❌ 硬编码路径
# 正确:使用os.path或pathlib处理路径
import os
filepath = os.path.join('config', 'settings.json') # ✅
with open(filepath, 'r') as file:
data = json.load(file)
小结
CSV文件要点
- CSV是简单的文本表格格式,适合结构化数据存储
- 使用
csv.reader()和csv.writer()读写基本CSV文件 - 使用
csv.DictReader()和csv.DictWriter()处理有标题的CSV文件 - 注意指定编码(通常使用
utf-8)和换行符处理(newline='')
JSON文件要点
- JSON是轻量级的数据交换格式,支持嵌套结构
- 使用
json.load()和json.dump()读写JSON文件 - 使用
json.loads()和json.dumps()处理JSON字符串 - JSON不支持所有Python类型,需要注意类型转换
选择指南
- 使用CSV:当处理简单的表格数据,需要与Excel或其他数据库交互时
- 使用JSON:当存储复杂、有层次的数据,或需要与Web API交互时
最佳实践
- 始终使用
with语句确保文件正确关闭 - 处理文件时考虑异常情况(文件不存在、权限不足等)
- 对于大型文件,考虑逐行处理而不是一次性加载到内存
- 保持编码一致性,推荐使用
utf-8编码
下一课我们将学习更现代的文件系统操作方法,使用pathlib模块让文件处理更加简洁和Python化。
练习编辑器
python
Loading...