23·模块六:文件与IO进阶

读写常见格式文件(CSV, JSON)

csvjsonfile-formats

第23课 - 读写常见格式文件(CSV, JSON)

学习目标

通过本课学习,你将能够:

  1. 使用 csv 模块读取和写入CSV文件
  2. 使用 json 模块解析和生成JSON格式数据
  3. 处理CSV文件中的特殊字符和分隔符
  4. 在Python数据结构与JSON格式之间进行相互转换
  5. 应用正确的异常处理处理文件格式错误

核心概念

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数据处理

要求:创建一个程序,完成以下任务:

  1. 读取products.csv文件(假设文件存在,包含产品名称、价格、库存量三列)
  2. 找出所有价格低于50元且库存大于10的产品
  3. 将筛选后的产品信息写入cheap_products.csv

预期输出示例

找到3个符合条件的产品,已保存到cheap_products.csv

练习2:JSON配置管理

要求:编写一个简单的配置管理系统:

  1. 创建一个JSON文件存储服务器配置
  2. 提供函数来读取、修改和保存配置
  3. 支持添加新的配置项

提示:可以创建一个ServerConfig类来封装这些操作

练习3:格式转换器

要求:实现CSV到JSON的转换器:

  1. 读取一个CSV文件
  2. 将每一行转换为JSON对象(使用标题行作为键名)
  3. 将所有行数据作为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交互时

最佳实践

  1. 始终使用with语句确保文件正确关闭
  2. 处理文件时考虑异常情况(文件不存在、权限不足等)
  3. 对于大型文件,考虑逐行处理而不是一次性加载到内存
  4. 保持编码一致性,推荐使用utf-8编码

下一课我们将学习更现代的文件系统操作方法,使用pathlib模块让文件处理更加简洁和Python化。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「现代文件系统操作(pathlib 模块)」 以巩固所学知识。