JSON 文件无处不在 — 从 Web API 到配置文件。让我们探索如何在 Python 中使用它们,并提供您可以立即使用的清晰示例。
基本 JSON作
将 JSON 写入文件
让我们从基础知识开始 — 将简单的字典保存到 JSON 文件:
import json
# Your data
user_data = {
"name": "Alice Smith",
"age": 28,
"email": "alice@example.com",
"interests": ["coding", "hiking", "photography"]
}
# Save to file
with open("user_data.json", "w") as file:
json.dump(user_data, file)
这里发生了什么?
- 'open()' 在写入模式下创建一个文件 (“w”)
- 'json.dump()' 将数据直接写入文件
- 'with' 语句确保文件正确关闭
- Python 会自动处理 JSON 转换
从文件中读取 JSON
读回文件同样简单:
# Read from file
with open("user_data.json", "r") as file:
loaded_data = json.load(file)
print(loaded_data["name"]) # Output: Alice Smith
print(loaded_data["interests"]) # Output: ['coding', 'hiking', 'photography']
使 JSON 文件可读
默认情况下,JSON 文件不进行格式化保存。让我们让它们更漂亮:
# Save with nice formatting
with open("user_data_pretty.json", "w") as file:
json.dump(user_data, file, indent=4)
这将创建一个如下所示的文件:
{
"name": "Alice Smith",
"age": 28,
"email": "alice@example.com",
"interests": [
"coding",
"hiking",
"photography"
]
}
'indent' 参数添加:
- 一致的间距
- 换行符
- 嵌套缩进
- 更好的人类可读性
处理复杂数据类型
Python 具有 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)
# Complex data with datetime
event_data = {
"event_name": "Conference",
"date": datetime.now(),
"attendees": ["Bob", "Carol", "Dave"]
}
# Save with custom encoder
with open("event_data.json", "w") as file:
json.dump(event_data, file, cls=DateTimeEncoder)
此代码:
- 为 datetime 对象创建自定义编码器
- 将日期时间转换为 ISO 格式字符串
- 保持与标准 JSON 的兼容性
真实示例
保存应用程序设置
以下是为您的应用程序创建设置管理器的方法:
class SettingsManager:
def __init__(self, settings_file="settings.json"):
self.settings_file = settings_file
self.settings = self.load_settings()
def load_settings(self):
try:
with open(self.settings_file, "r") as file:
return json.load(file)
except FileNotFoundError:
return self.get_default_settings()
def save_settings(self):
with open(self.settings_file, "w") as file:
json.dump(self.settings, file, indent=4)
def get_default_settings(self):
return {
"theme": "light",
"font_size": 12,
"notifications": True,
"language": "en"
}
def update_setting(self, key, value):
self.settings[key] = value
self.save_settings()
# Usage example
settings = SettingsManager()
settings.update_setting("theme", "dark")
缓存 API 响应
以下是缓存 API 数据的实际示例:
import json
import time
from pathlib import Path
class APICache:
def __init__(self, cache_file="api_cache.json"):
self.cache_file = Path(cache_file)
self.cache = self.load_cache()
def load_cache(self):
if self.cache_file.exists():
with open(self.cache_file, "r") as file:
return json.load(file)
return {}
def save_cache(self):
with open(self.cache_file, "w") as file:
json.dump(self.cache, file)
def get_data(self, key, max_age=3600):
"""Get data from cache if it's fresh, return None if expired"""
if key in self.cache:
entry = self.cache[key]
if time.time() - entry["timestamp"] < max_age:
return entry["data"]
return None
def set_data(self, key, data):
"""Save data to cache with current timestamp"""
self.cache[key] = {
"data": data,
"timestamp": time.time()
}
self.save_cache()
# Example usage
cache = APICache()
data = cache.get_data("user_profile")
if data is None:
# Simulate API call
data = {"name": "Alice", "last_seen": "2024-01-01"}
cache.set_data("user_profile", data)
使用嵌套数据
在处理复杂的嵌套结构(如配置文件)时:
def save_config(config, filename="config.json"):
"""Save nested configuration with error handling"""
try:
with open(filename, "w") as file:
json.dump(config, file, indent=2)
return True
except Exception as e:
print(f"Error saving config: {e}")
return False
# Complex nested configuration
app_config = {
"database": {
"host": "localhost",
"port": 5432,
"credentials": {
"username": "admin",
"password": "secret"
}
},
"server": {
"host": "0.0.0.0",
"port": 8080,
"debug": True,
"allowed_origins": [
"http://localhost:3000",
"https://example.com"
]
},
"logging": {
"level": "INFO",
"handlers": ["console", "file"],
"file_config": {
"path": "/var/log/app.log",
"max_size": 1024000,
"backup_count": 3
}
}
}
save_config(app_config)
错误处理和验证
始终验证您的 JSON作:
def safe_write_json(data, filename):
"""Safely write data to a JSON file with validation"""
try:
# First validate by encoding to string
json_string = json.dumps(data)
# Verify it can be parsed back
json.loads(json_string)
# If we get here, the JSON is valid
with open(filename, "w") as file:
file.write(json_string)
return True
except json.JSONDecodeError as e:
print(f"Invalid JSON data: {e}")
return False
except IOError as e:
print(f"File error: {e}")
return False
except Exception as e:
print(f"Unexpected error: {e}")
return False
# Example usage with invalid data
invalid_data = {
"name": "Test",
"value": float('nan') # This is not valid JSON
}
success = safe_write_json(invalid_data, "test.json")
print(f"Save successful: {success}")
性能提示
使用大型 JSON 文件时:
def read_json_in_chunks(filename, chunk_size=1024*8):
"""Read a large JSON file efficiently"""
with open(filename, "r") as file:
decoder = json.JSONDecoder()
buffer = ""
while True:
chunk = file.read(chunk_size)
if not chunk:
break
buffer += chunk
try:
while buffer:
result, index = decoder.raw_decode(buffer)
buffer = buffer[index:].lstrip()
yield result
except json.JSONDecodeError:
# Incomplete JSON data, read more
continue
# Example usage for large files
for item in read_json_in_chunks("large_file.json"):
process_item(item)
性能要点:
- 对大文件使用块
- 考虑使用 'ujson' 来提高速度(如果可用)
- 仅在需要时保持文件可读
- 使用适当的文件权限
常见问题和解决方案
处理 Unicode
def write_unicode_json(data, filename):
"""Write JSON with proper Unicode handling"""
with open(filename, "w", encoding="utf-8") as file:
json.dump(data, file, ensure_ascii=False)
# Example with Unicode data
unicode_data = {
"name": "José",
"city": "S~ao Paulo",
"greeting": "你好"
}
write_unicode_json(unicode_data, "unicode_data.json")
处理特殊类型
def convert_to_serializable(obj):
"""Convert special Python types to JSON-serializable formats"""
if isinstance(obj, (datetime, date)):
return obj.isoformat()
elif isinstance(obj, set):
return list(obj)
elif isinstance(obj, bytes):
return obj.decode('utf-8')
raise TypeError(f"Type {type(obj)} not serializable")
# Usage example
complex_data = {
"date": datetime.now(),
"tags": {"python", "json", "tutorial"},
"binary": b"Hello World"
}
with open("complex_data.json", "w") as file:
json.dump(complex_data, file, default=convert_to_serializable)
记得:
- 始终使用正确的编码
- 显式处理特殊数据类型
- 保存前验证 JSON
- 使用适当的错误处理
- 考虑文件权限和路径
这些示例涵盖了 Python 中最常见的 JSON 文件作。选择最适合您特定需求的方法,并在用于生产之前始终使用样本数据进行测试。