第85集:JSON文件操作

学习目标

  • 理解JSON数据格式的基本概念
  • 掌握json模块的使用方法
  • 学会读取和写入JSON文件
  • 掌握JSON数据的序列化和反序列化
  • 学会处理JSON文件中的常见问题

一、JSON概述

1.1 什么是JSON

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它基于JavaScript的一个子集,但是完全独立于语言。

1.2 JSON的特点

  • 轻量级:数据格式简洁,易于传输
  • 可读性:人类可读,易于理解和调试
  • 跨语言:支持多种编程语言
  • 结构化:支持嵌套的数据结构

1.3 JSON数据类型

JSON类型 Python类型 示例
对象(object) dict {"name": "张三", "age": 25}
数组(array) list [1, 2, 3, 4, 5]
字符串(string) str "Hello, World!"
数字(number) int/float 42, 3.14
布尔值(boolean) bool true, false
null None null

1.4 JSON格式示例

{
  "name": "张三",
  "age": 25,
  "is_student": true,
  "hobbies": ["读书", "游泳", "编程"],
  "address": {
    "city": "北京",
    "district": "朝阳区"
  },
  "scores": {
    "math": 95,
    "english": 88,
    "physics": 92
  }
}

二、json模块简介

2.1 导入json模块

import json

2.2 json模块的主要函数

  • **json.dumps()**:将Python对象转换为JSON字符串
  • **json.dump()**:将Python对象写入JSON文件
  • **json.loads()**:将JSON字符串转换为Python对象
  • **json.load()**:从JSON文件读取并转换为Python对象

三、JSON序列化

3.1 使用dumps()转换为JSON字符串

import json

data = {
    "name": "张三",
    "age": 25,
    "is_student": True
}

json_str = json.dumps(data)
print(json_str)
# 输出:{"name": "\u5f20\u4e09", "age": 25, "is_student": true}

3.2 使用ensure_ascii参数

默认情况下,非ASCII字符会被转义。使用ensure_ascii=False可以保留原始字符。

import json

data = {"name": "张三", "age": 25}

# 默认:转义非ASCII字符
json_str1 = json.dumps(data)
print(json_str1)
# 输出:{"name": "\u5f20\u4e09", "age": 25}

# 保留原始字符
json_str2 = json.dumps(data, ensure_ascii=False)
print(json_str2)
# 输出:{"name": "张三", "age": 25}

3.3 使用indent参数格式化输出

使用indent参数可以美化JSON输出。

import json

data = {
    "name": "张三",
    "age": 25,
    "hobbies": ["读书", "游泳"]
}

json_str = json.dumps(data, indent=2, ensure_ascii=False)
print(json_str)

3.4 使用sort_keys参数排序键

使用sort_keys=True可以按键名排序。

import json

data = {
    "name": "张三",
    "age": 25,
    "city": "北京"
}

json_str = json.dumps(data, sort_keys=True, indent=2, ensure_ascii=False)
print(json_str)

四、JSON反序列化

4.1 使用loads()转换为Python对象

import json

json_str = '{"name": "张三", "age": 25, "is_student": true}'
data = json.loads(json_str)
print(data)
# 输出:{'name': '张三', 'age': 25, 'is_student': True}

4.2 访问JSON数据

import json

json_str = '{"name": "张三", "age": 25, "hobbies": ["读书", "游泳"]}'
data = json.loads(json_str)

print(data["name"])
print(data["age"])
print(data["hobbies"][0])

五、JSON文件操作

5.1 写入JSON文件

使用json.dump()函数将Python对象写入JSON文件。

import json

data = {
    "name": "张三",
    "age": 25,
    "is_student": True,
    "hobbies": ["读书", "游泳", "编程"]
}

with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

5.2 读取JSON文件

使用json.load()函数从JSON文件读取数据。

import json

with open('data.json', 'r', encoding='utf-8') as f:
    data = json.load(f)
    print(data)

六、JSON数据处理

6.1 处理嵌套JSON数据

import json

json_str = '''
{
  "name": "张三",
  "address": {
    "city": "北京",
    "district": "朝阳区"
  },
  "scores": {
    "math": 95,
    "english": 88
  }
}
'''

data = json.loads(json_str)
print(data["address"]["city"])
print(data["scores"]["math"])

6.2 处理JSON数组

import json

json_str = '''
[
  {"name": "张三", "age": 25},
  {"name": "李四", "age": 30},
  {"name": "王五", "age": 28}
]
'''

data = json.loads(json_str)
for person in data:
    print(f"{person['name']}: {person['age']}岁")

6.3 筛选JSON数据

import json

json_str = '''
[
  {"name": "张三", "age": 25, "score": 95},
  {"name": "李四", "age": 30, "score": 88},
  {"name": "王五", "age": 28, "score": 92}
]
'''

data = json.loads(json_str)
filtered = [person for person in data if person["score"] > 90]
print(filtered)

6.4 修改JSON数据

import json

json_str = '{"name": "张三", "age": 25}'
data = json.loads(json_str)

data["age"] = 26
data["city"] = "北京"

new_json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(new_json_str)

七、JSON与数据结构转换

7.1 字典转换为JSON

import json

data = {
    "name": "张三",
    "age": 25,
    "city": "北京"
}

json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)

7.2 列表转换为JSON

import json

data = [1, 2, 3, 4, 5]

json_str = json.dumps(data, indent=2)
print(json_str)

7.3 嵌套结构转换为JSON

import json

data = {
    "students": [
        {"name": "张三", "age": 25},
        {"name": "李四", "age": 30}
    ],
    "teacher": {
        "name": "王老师",
        "subject": "数学"
    }
}

json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)

八、JSON文件常见问题

8.1 编码问题

import json

# 写入JSON文件时指定编码
data = {"name": "张三", "age": 25}
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:
    data = json.load(f)
    print(data)

8.2 处理不支持的Python类型

Python的某些类型(如datetime、set等)不能直接序列化为JSON。

import json
from datetime import datetime

# 错误示例:datetime不能直接序列化
data = {"time": datetime.now()}
try:
    json_str = json.dumps(data)
except TypeError as e:
    print(f"错误:{e}")

# 解决方法:转换为字符串
data = {"time": datetime.now().isoformat()}
json_str = json.dumps(data)
print(json_str)

8.3 处理JSON解析错误

import json

# 错误的JSON字符串
invalid_json = '{"name": "张三", "age": 25'

try:
    data = json.loads(invalid_json)
except json.JSONDecodeError as e:
    print(f"JSON解析错误:{e}")

8.4 处理大JSON文件

对于大JSON文件,可以使用ijson库进行流式处理。

# 需要安装:pip install ijson
import ijson

with open('large_file.json', 'rb') as f:
    for item in ijson.items(f, 'item'):
        process(item)

九、JSON高级操作

9.1 自定义JSON编码器

import json
from datetime import datetime

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

data = {
    "name": "张三",
    "time": datetime.now()
}

json_str = json.dumps(data, cls=DateTimeEncoder, ensure_ascii=False, indent=2)
print(json_str)

9.2 自定义JSON解码器

import json
from datetime import datetime

def datetime_decoder(obj):
    if 'time' in obj:
        obj['time'] = datetime.fromisoformat(obj['time'])
    return obj

json_str = '{"name": "张三", "time": "2024-01-01T12:00:00"}'
data = json.loads(json_str, object_hook=datetime_decoder)
print(data)

9.3 合并JSON数据

import json

json1 = '{"name": "张三", "age": 25}'
json2 = '{"city": "北京", "score": 95}'

data1 = json.loads(json1)
data2 = json.loads(json2)

merged = {**data1, **data2}
json_str = json.dumps(merged, ensure_ascii=False, indent=2)
print(json_str)

9.4 JSON数据验证

import json

def validate_json(json_str):
    try:
        data = json.loads(json_str)
        return True, data
    except json.JSONDecodeError as e:
        return False, str(e)

json_str = '{"name": "张三", "age": 25}'
is_valid, result = validate_json(json_str)
print(f"是否有效:{is_valid}")
print(f"结果:{result}")

十、最佳实践

10.1 使用with语句

# 推荐
with open('data.json', 'r', encoding='utf-8') as f:
    data = json.load(f)

# 不推荐
f = open('data.json', 'r', encoding='utf-8')
data = json.load(f)
f.close()

10.2 指定编码方式

# 推荐
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False)

# 不推荐
with open('data.json', 'w') as f:
    json.dump(data, f)

10.3 格式化JSON输出

# 推荐:使用indent参数
json_str = json.dumps(data, indent=2, ensure_ascii=False)

# 不推荐:不使用indent参数
json_str = json.dumps(data)

10.4 异常处理

import json

try:
    with open('data.json', 'r', encoding='utf-8') as f:
        data = json.load(f)
except FileNotFoundError:
    print('文件不存在')
except json.JSONDecodeError:
    print('JSON格式错误')
except Exception as e:
    print(f'发生错误:{e}')

十一、总结

本集学习了JSON文件操作的知识:

  • JSON数据格式的基本概念和数据类型
  • json模块的使用方法
  • JSON数据的序列化和反序列化
  • JSON文件的读取和写入
  • JSON数据的处理和转换
  • JSON文件常见问题和最佳实践

JSON是一种广泛使用的数据交换格式,在Web开发、API接口、配置文件等场景中非常重要。下一集我们将学习XML文件操作。

十二、练习题

  1. 创建一个JSON文件,包含学生信息(姓名、年龄、成绩、爱好),然后读取并显示。
  2. 编写一个函数,将字典列表转换为JSON字符串。
  3. 实现一个函数,筛选出成绩大于90分的学生。
  4. 编写一个程序,合并两个JSON文件的数据。
  5. 实现一个自定义JSON编码器,处理datetime对象。
  6. 编写一个函数,验证JSON字符串的有效性。
  7. 实现一个程序,统计JSON数组中每个城市的平均成绩。
  8. 编写一个程序,将CSV文件转换为JSON文件。
« 上一篇 CSV文件操作 下一篇 » XML文件操作