1. JSON与CSV格式深度解析
1.1 JSON格式的本质与应用场景
JSON(JavaScript Object Notation)本质上是一种轻量级的数据交换格式。我第一次接触JSON是在2013年开发一个天气预报API接口时,当时就被它比XML更简洁的结构所吸引。JSON采用完全独立于语言的文本格式,但使用了类似于C语言家族的习惯(包括C、C++、C#、Java、JavaScript、Python等)。
JSON的核心数据结构包含两种:
- 键值对集合:在各种语言中被实现为对象、记录、字典或哈希表
- 有序值列表:通常以数组或列表的形式存在
典型JSON文件示例:
json复制{
"employee": {
"name": "张三",
"age": 30,
"skills": ["Python", "SQL", "数据分析"],
"projects": [
{
"name": "销售分析系统",
"duration": 6
}
]
}
}
JSON在以下场景中表现尤为出色:
- Web API数据传输(90%以上的现代API使用JSON)
- 配置文件存储(如VS Code的设置文件)
- NoSQL数据库文档存储(如MongoDB)
- 前端与后端之间的数据交换
注意:JSON虽然源自JavaScript,但现代编程语言都提供了完善的JSON支持,完全不必局限于JavaScript环境使用。
1.2 CSV格式的特点与适用场景
CSV(Comma-Separated Values)是我在数据分析工作中接触最频繁的格式之一。记得第一次处理包含10万行销售数据的CSV文件时,就被它的简单高效所震撼。CSV的本质是以纯文本形式存储表格数据(数字和文本),每行表示一条记录,字段间用特定分隔符(通常是逗号)隔开。
典型CSV文件示例:
code复制date,product,quantity,price
2023-01-01,A1001,5,299.99
2023-01-02,B2002,3,599.50
CSV格式的显著优势包括:
- 极高的可读性(可直接用文本编辑器查看)
- 极低的存储开销(相比Excel可节省50%以上空间)
- 几乎被所有数据处理工具支持
- 适合批量导入/导出数据库记录
但CSV也存在一些局限性:
- 缺乏标准规范(不同系统生成的CSV可能有差异)
- 无法直接表示层次化数据
- 对特殊字符处理需要额外注意(如包含逗号的字段)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Python处理JSON的完整指南
2.1 标准库json模块详解
Python内置的json模块是我日常使用频率最高的模块之一。它提供了非常直观的API来处理JSON数据:
python复制import json
# 将Python对象转为JSON字符串
data = {"name": "李四", "age": 28}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
# 将JSON字符串转为Python对象
restored_data = json.loads(json_str)
print(restored_data["name"])
关键参数说明:
ensure_ascii=False:允许非ASCII字符正常显示(中文等)indent=2:美化输出,使用2空格缩进sort_keys=True:按键名排序输出(适合需要确定性的场景)
文件操作同样简单:
python复制# 写入JSON文件
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f)
# 读取JSON文件
with open("data.json", "r", encoding="utf-8") as f:
loaded_data = json.load(f)
2.2 高级JSON处理技巧
在实际项目中,我总结出几个非常有用的进阶技巧:
- 处理日期时间对象:
python复制from datetime import datetime
class DateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
data = {"created_at": datetime.now()}
json_str = json.dumps(data, cls=DateTimeEncoder)
- 处理自定义对象:
python复制class User:
def __init__(self, name, age):
self.name = name
self.age = age
def user_encoder(obj):
if isinstance(obj, User):
return {"name": obj.name, "age": obj.age}
raise TypeError(f"{obj} is not JSON serializable")
user = User("王五", 35)
json.dumps(user, default=user_encoder)
- 大数据量处理:对于超大JSON文件,建议使用ijson等流式处理库,避免内存溢出。
3. Python操作CSV的实战技巧
3.1 基础读写操作
Python的csv模块提供了强大的CSV处理能力。我经常使用的模式包括:
基本写入:
python复制import csv
with open("data.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["姓名", "年龄", "城市"]) # 写入表头
writer.writerow(["张三", 30, "北京"])
writer.writerow(["李四", 25, "上海"])
带字典的读写(更推荐):
python复制# 写入
with open("data_dict.csv", "w", newline="", encoding="utf-8") as f:
fieldnames = ["name", "age", "city"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({"name": "张三", "age": 30, "city": "北京"})
# 读取
with open("data_dict.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], row["city"])
3.2 处理复杂CSV文件
在实际工作中,经常会遇到各种"非标准"CSV文件。以下是几种常见情况的处理方法:
- 不同分隔符的文件:
python复制# 使用分号分隔
with open("semicolon.csv", "r") as f:
reader = csv.reader(f, delimiter=";")
for row in reader:
print(row)
- 包含引号的字段:
python复制# 处理带引号的字段
with open("quoted.csv", "r") as f:
reader = csv.reader(f, quotechar='"', escapechar='\\')
for row in reader:
print(row)
- 处理空单元格:
python复制# 将空字符串转为None
def process_empty_cells(row):
return [cell if cell != "" else None for cell in row]
with open("data_with_empty.csv", "r") as f:
reader = csv.reader(f)
processed_rows = [process_empty_cells(row) for row in reader]
4. JSON与CSV的相互转换实战
4.1 CSV转JSON的完整流程
这是我经常需要执行的一个任务,特别是在数据预处理阶段。下面是一个完整的示例:
python复制import csv
import json
def csv_to_json(csv_file, json_file):
# 读取CSV文件
with open(csv_file, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
data = [row for row in reader]
# 写入JSON文件
with open(json_file, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 验证转换结果
with open(json_file, "r", encoding="utf-8") as f:
loaded_data = json.load(f)
print(f"成功转换 {len(loaded_data)} 条记录")
return loaded_data
# 使用示例
csv_to_json("input.csv", "output.json")
4.2 JSON转CSV的实现方案
反向转换同样重要,特别是需要将API获取的数据导出为表格形式时:
python复制def json_to_csv(json_file, csv_file):
# 读取JSON文件
with open(json_file, "r", encoding="utf-8") as f:
data = json.load(f)
# 提取所有可能的字段(处理不统一的数据结构)
all_fields = set()
for item in data:
all_fields.update(item.keys())
fieldnames = sorted(all_fields)
# 写入CSV文件
with open(csv_file, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for item in data:
# 处理可能缺失的字段
row = {field: item.get(field, "") for field in fieldnames}
writer.writerow(row)
print(f"成功转换 {len(data)} 条记录")
提示:对于大型数据转换,建议使用pandas库,它提供了更高效的
read_csv()和to_json()方法,性能比纯Python实现高10倍以上。
5. 常见问题与性能优化
5.1 编码问题解决方案
在我处理过的数百个数据项目中,编码问题是最常见的坑之一。以下是我的经验总结:
- UTF-8 BOM问题:
python复制# 处理带BOM的UTF-8文件
with open("data.csv", "r", encoding="utf-8-sig") as f:
reader = csv.reader(f)
for row in reader:
print(row)
- 混合编码文件处理:
python复制from chardet import detect
def detect_encoding(file_path):
with open(file_path, "rb") as f:
rawdata = f.read(10000) # 读取前10000字节用于检测
return detect(rawdata)["encoding"]
encoding = detect_encoding("unknown_encoding.csv")
with open("unknown_encoding.csv", "r", encoding=encoding) as f:
reader = csv.reader(f)
for row in reader:
print(row)
5.2 大文件处理策略
当处理GB级别的JSON/CSV文件时,内存使用变得至关重要。以下是我的优化方案:
- 流式处理JSON:
python复制import ijson
def process_large_json(file_path):
with open(file_path, "r", encoding="utf-8") as f:
# 使用items前缀处理数组中的对象
parser = ijson.parse(f)
for prefix, event, value in parser:
if prefix.endswith(".name") and event == "string":
print(f"Processing: {value}")
- 分块处理CSV:
python复制def process_large_csv(file_path, chunk_size=10000):
with open(file_path, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
chunk = []
for i, row in enumerate(reader):
chunk.append(row)
if len(chunk) >= chunk_size:
process_chunk(chunk) # 自定义处理函数
chunk = []
if chunk: # 处理剩余记录
process_chunk(chunk)
def process_chunk(chunk):
print(f"Processing chunk with {len(chunk)} records")
# 实际处理逻辑...
- 使用Dask或Pandas分块读取:
python复制# 使用Pandas分块读取
import pandas as pd
chunk_iter = pd.read_csv("huge_file.csv", chunksize=50000)
for chunk in chunk_iter:
process_data(chunk)
5.3 性能对比与工具选择
在我的性能测试中(处理1GB销售数据文件):
| 方法 | 耗时 | 内存占用 | 适用场景 |
|---|---|---|---|
| Python csv模块 | 45s | 1.2GB | 需要精细控制处理逻辑 |
| Pandas read_csv | 12s | 2.5GB | 快速数据分析和简单转换 |
| Dask | 18s | 800MB | 超大文件,分布式处理 |
| Polars | 9s | 1.8GB | 极速处理,类Pandas API |
选择建议:
- 小型文件(<100MB):直接使用Pandas
- 中型文件(100MB-1GB):考虑Polars
- 大型文件(>1GB):使用Dask或分块处理
- 需要特殊处理逻辑:使用Python标准库
6. 实际项目案例分享
6.1 电商数据分析管道
去年我构建的一个电商数据分析系统,完美结合了JSON和CSV的优势:
- 原始数据:从API获取JSON格式的订单数据
json复制{
"order_id": "10001",
"customer": {
"id": "cus_123",
"name": "张三"
},
"items": [
{"sku": "A100", "qty": 2, "price": 99.99},
{"sku": "B200", "qty": 1, "price": 199.99}
],
"created_at": "2023-05-01T10:30:00Z"
}
- 数据处理流程:
- 将嵌套JSON扁平化为CSV友好格式
- 提取关键指标到CSV文件供BI工具使用
- 保留原始JSON用于详细查询
关键转换代码:
python复制def flatten_order(order):
flat = {
"order_id": order["order_id"],
"customer_id": order["customer"]["id"],
"customer_name": order["customer"]["name"],
"item_count": len(order["items"]),
"total_amount": sum(item["qty"] * item["price"] for item in order["items"]),
"created_date": order["created_at"][:10]
}
return flat
6.2 配置文件管理系统
另一个典型场景是管理应用的配置系统:
- 开发环境:使用JSON配置文件(支持复杂结构)
json复制{
"database": {
"host": "localhost",
"port": 5432,
"credentials": {
"username": "dev_user",
"password": "dev_pass"
}
},
"logging": {
"level": "DEBUG",
"path": "/tmp/app.log"
}
}
- 生产环境:转换为CSV供运维人员简单修改
code复制section,key,value
database,host,prod-db.example.com
database,port,5432
database.credentials,username,prod_user
database.credentials,password,prod_pass_123
logging,level,INFO
logging,path,/var/log/app.log
转换工具实现:
python复制def json_config_to_csv(json_file, csv_file):
def flatten_dict(d, prefix=""):
items = []
for k, v in d.items():
full_key = f"{prefix}.{k}" if prefix else k
if isinstance(v, dict):
items.extend(flatten_dict(v, full_key))
else:
items.append((full_key, str(v)))
return items
with open(json_file, "r") as f:
config = json.load(f)
flat_items = flatten_dict(config)
with open(csv_file, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["section", "key", "value"])
for key, value in flat_items:
if "." in key:
section, subkey = key.rsplit(".", 1)
else:
section, subkey = "", key
writer.writerow([section, subkey, value])
7. 最佳实践与经验总结
7.1 JSON处理黄金法则
经过多年实践,我总结了以下JSON处理原则:
- 始终明确编码:统一使用UTF-8编码,读写时显式声明
python复制with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f)
- 验证JSON数据完整性:特别是在处理API响应时
python复制def safe_json_loads(json_str):
try:
return json.loads(json_str)
except json.JSONDecodeError as e:
print(f"Invalid JSON: {e}")
return None
- 使用JSON Schema验证复杂结构:
python复制from jsonschema import validate
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "number", "minimum": 0}
},
"required": ["name"]
}
validate(instance={"name": "张三", "age": 30}, schema=schema)
7.2 CSV处理注意事项
在CSV处理方面,这些经验可以帮你避开很多坑:
- 始终指定newline=""参数:
python复制# 在Windows上特别重要,避免空行问题
with open("data.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
- 处理字段中的特殊字符:
python复制# 使用quotechar和quoting处理包含分隔符的字段
with open("data.csv", "w", newline="") as f:
writer = csv.writer(f, quoting=csv.QUOTE_MINIMAL, quotechar='"')
writer.writerow(["正常字段", "包含,逗号的字段", "包含\"引号的字段"])
- 性能敏感场景使用csv.DictReader的替代方案:
python复制# 更快的替代方案(牺牲一些灵活性)
def fast_csv_reader(file_path):
with open(file_path, "r", encoding="utf-8") as f:
header = next(f).strip().split(",")
for line in f:
yield dict(zip(header, line.strip().split(",")))
7.3 调试技巧
当遇到JSON/CSV处理问题时,我的调试流程通常是:
- 检查文件开头和结尾:
python复制# 查看文件前100字节
with open("problematic.json", "rb") as f:
print(f.read(100))
# 查看文件最后100字节
with open("problematic.json", "rb") as f:
f.seek(-100, 2) # 移动到文件末尾前100字节
print(f.read())
- 使用更详细的错误捕获:
python复制try:
with open("data.csv", "r") as f:
reader = csv.reader(f)
for row in reader:
process_row(row)
except csv.Error as e:
print(f"CSV error at line {reader.line_num}: {e}")
- 对于编码问题,使用十六进制查看:
python复制def hex_view(file_path, num_bytes=100):
with open(file_path, "rb") as f:
data = f.read(num_bytes)
print(" ".join(f"{b:02x}" for b in data))
这些年来,我处理过各种"奇怪"的数据文件,包括:
- 混合了多种编码的CSV文件
- 包含BOM头的UTF-8文件
- 行尾不一致的CSV(混合\n和\r\n)
- 嵌套层级超过10层的JSON配置文件
- 单个文件超过20GB的JSON日志
关键是要保持耐心,逐步缩小问题范围,并使用合适的工具进行分析。
