Python 文件与输入输出:6.4 JSON 文件处理

在现代编程中,数据的存储和交换是一个至关重要的环节。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,因其易于人类阅读和编写,同时也易于机器解析和生成,广泛应用于数据传输和存储。Python 提供了内置的 json 模块,使得处理 JSON 数据变得简单而高效。

1. JSON 格式简介

JSON 格式使用键值对的方式来表示数据,支持多种数据类型,包括字符串、数字、布尔值、数组和对象。以下是一个简单的 JSON 示例:

{
    "name": "Alice",
    "age": 30,
    "is_student": false,
    "courses": ["Math", "Science"],
    "address": {
        "city": "New York",
        "zip": "10001"
    }
}

优点

  • 可读性强:JSON 格式简单明了,易于理解。
  • 语言无关性:JSON 可以被多种编程语言解析和生成。
  • 轻量级:相较于 XML 等格式,JSON 更加简洁,数据传输时占用更少的带宽。

缺点

  • 数据类型限制:JSON 不支持日期、时间等复杂数据类型,需手动处理。
  • 安全性问题:在解析不可信的 JSON 数据时,可能会引发安全问题。

2. Python 中的 JSON 处理

Python 的 json 模块提供了两个主要的功能:将 Python 对象编码为 JSON 格式(序列化),以及将 JSON 格式解码为 Python 对象(反序列化)。

2.1 JSON 序列化

使用 json.dump()json.dumps() 方法可以将 Python 对象转换为 JSON 格式。

  • json.dump(obj, file):将 Python 对象 obj 写入到文件 file 中。
  • json.dumps(obj):将 Python 对象 obj 转换为 JSON 字符串。

示例代码

import json

# Python 对象
data = {
    "name": "Alice",
    "age": 30,
    "is_student": False,
    "courses": ["Math", "Science"],
    "address": {
        "city": "New York",
        "zip": "10001"
    }
}

# 将 Python 对象写入 JSON 文件
with open('data.json', 'w') as json_file:
    json.dump(data, json_file, indent=4)  # indent=4 使输出格式化

# 将 Python 对象转换为 JSON 字符串
json_string = json.dumps(data, indent=4)
print(json_string)

注意事项

  • 使用 indent 参数可以使输出的 JSON 更加美观,便于阅读。
  • 在写入文件时,确保文件路径正确,且具有写入权限。

2.2 JSON 反序列化

使用 json.load()json.loads() 方法可以将 JSON 格式的数据转换为 Python 对象。

  • json.load(file):从文件 file 中读取 JSON 数据并转换为 Python 对象。
  • json.loads(json_string):将 JSON 字符串 json_string 转换为 Python 对象。

示例代码

import json

# 从 JSON 文件读取数据
with open('data.json', 'r') as json_file:
    data_loaded = json.load(json_file)
    print(data_loaded)

# 从 JSON 字符串读取数据
json_string = '{"name": "Alice", "age": 30, "is_student": false}'
data_from_string = json.loads(json_string)
print(data_from_string)

注意事项

  • 在读取 JSON 文件时,确保文件存在且格式正确,否则会引发 json.JSONDecodeError
  • 处理 JSON 数据时,注意数据类型的转换,特别是布尔值和数字。

3. 处理复杂数据类型

如前所述,JSON 不支持某些复杂数据类型(如日期)。在这种情况下,我们需要自定义序列化和反序列化方法。

自定义序列化

可以通过定义一个自定义的编码器来处理复杂数据类型。

示例代码

import json
from datetime import datetime

# 自定义 JSON 编码器
class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()  # 转换为 ISO 格式字符串
        return super().default(obj)

# 使用自定义编码器
data_with_date = {
    "name": "Alice",
    "date_of_birth": datetime(1993, 5, 17)
}

json_string = json.dumps(data_with_date, cls=DateTimeEncoder, indent=4)
print(json_string)

自定义反序列化

在反序列化时,可以通过自定义函数来处理特定格式的数据。

示例代码

import json
from datetime import datetime

# 自定义反序列化函数
def custom_decoder(dct):
    if 'date_of_birth' in dct:
        dct['date_of_birth'] = datetime.fromisoformat(dct['date_of_birth'])
    return dct

# JSON 字符串
json_string = '{"name": "Alice", "date_of_birth": "1993-05-17T00:00:00"}'

# 使用自定义解码器
data = json.loads(json_string, object_hook=custom_decoder)
print(data)
print(data['date_of_birth'].year)  # 输出年份

注意事项

  • 自定义序列化和反序列化时,确保数据的完整性和准确性。
  • 处理日期和时间时,注意时区问题。

4. 总结

JSON 是一种非常流行的数据交换格式,Python 的 json 模块使得处理 JSON 数据变得简单而高效。通过序列化和反序列化,我们可以轻松地在 Python 对象和 JSON 数据之间进行转换。尽管 JSON 有其优缺点,但在大多数情况下,它是一个非常实用的选择。

在处理 JSON 数据时,务必注意数据类型的转换和文件的读写权限,必要时可以自定义序列化和反序列化方法,以满足特定需求。通过合理使用 JSON,我们可以在数据存储和交换中实现更高的效率和灵活性。