技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
serialize-data-formats【数据与研究】跨常见格式进行数据序列化和反序列化,包括 JSON、XML、YAML、Protocol Buffers、 MessagePack 和 Apache Arrow/Parquet。涵盖格式选择标准、编码/解码模式、性能权衡 和互操作性考虑。适用于选择 API 通信的线路格式、将结构化数据持久化到磁盘、在不同 语言编写的系统之间交换数据、优化传输大小或解析速度,以及从一种序列化格式迁移到另一种。
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
为您的用例选择和实现正确的数据序列化格式,确保编码/解码正确且关注性能。
| 格式 | 人类可读 | 模式 | 大小 | 速度 | 最适用于 |
|---|---|---|---|---|---|
| JSON | 是 | 可选(JSON Schema) | 中等 | 中等 | REST API、配置、广泛互操作 |
| XML | 是 | XSD、DTD | 大 | 慢 | 企业/遗留系统、SOAP、文档 |
| YAML | 是 | 可选 | 中等 | 慢 | 配置文件、CI/CD、Kubernetes |
| Protocol Buffers | 否 | 必需(.proto) | 小 | 快 | gRPC、微服务、移动端 |
| MessagePack | 否 | 无 | 小 | 快 | 实时、嵌入式、Redis |
| Arrow/Parquet | 否 | 内置 | 非常小 | 非常快 | 分析、列式查询、数据湖 |
决策树:
预期结果: 格式已选择,并记录了与用例要求匹配的理由。 失败处理: 如果需求冲突(如既要人类可读又要快速),优先考虑主要用例并记录权衡。
import json
from datetime import datetime, date
from dataclasses import dataclass, asdict
@dataclass
class Measurement:
sensor_id: str
value: float
unit: str
timestamp: datetime
# Custom encoder for non-standard types
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, date):
return obj.isoformat()
if isinstance(obj, bytes):
import base64
return base64.b64encode(obj).decode('ascii')
return super().default(obj)
# Serialize
measurement = Measurement("sensor-01", 23.5, "celsius", datetime.now())
json_str = json.dumps(asdict(measurement), cls=CustomEncoder, indent=2)
# Deserialize
data = json.loads(json_str)
# R: JSON with jsonlite
library(jsonlite)
# Serialize
df <- data.frame(sensor_id = "sensor-01", value = 23.5, unit = "celsius")
json_str <- jsonlite::toJSON(df, auto_unbox = TRUE, pretty = TRUE)
# Deserialize
df_back <- jsonlite::fromJSON(json_str)
预期结果: 往返序列化准确保留所有数据类型。 失败处理: 如果类型丢失(如日期变成字符串),在反序列化步骤中添加显式类型转换。
定义模式(.proto 文件):
syntax = "proto3";
package sensors;
message Measurement {
string sensor_id = 1;
double value = 2;
string unit = 3;
int64 timestamp_ms = 4; // Unix milliseconds
}
message MeasurementBatch {
repeated Measurement measurements = 1;
}
生成和使用:
# Generate Python code
protoc --python_out=. sensors.proto
# Generate Go code
protoc --go_out=. sensors.proto
from sensors_pb2 import Measurement, MeasurementBatch
import time
# Serialize
m = Measurement(
sensor_id="sensor-01",
value=23.5,
unit="celsius",
timestamp_ms=int(time.time() * 1000)
)
binary = m.SerializeToString() # Compact binary
# Deserialize
m2 = Measurement()
m2.ParseFromString(binary)
预期结果: 二进制输出比等效的 JSON 小 3-10 倍。
失败处理: 如果 protoc 不可用,使用语言原生的 protobuf 库(如 Python 的 betterproto)。
import msgpack
from datetime import datetime
# Custom packing for datetime
def encode_datetime(obj):
if isinstance(obj, datetime):
return {"__datetime__": True, "s": obj.isoformat()}
return obj
def decode_datetime(obj):
if "__datetime__" in obj:
return datetime.fromisoformat(obj["s"])
return obj
data = {"sensor_id": "sensor-01", "value": 23.5, "ts": datetime.now()}
# Serialize (smaller than JSON, faster than JSON)
packed = msgpack.packb(data, default=encode_datetime)
# Deserialize
unpacked = msgpack.unpackb(packed, object_hook=decode_datetime, raw=False)
预期结果: MessagePack 输出对于典型载荷比 JSON 小 15-30%。 失败处理: 如果某种语言缺乏 MessagePack 支持,退回到 JSON 加压缩(gzip)。
import pyarrow as pa
import pyarrow.parquet as pq
import pandas as pd
# Create data
df = pd.DataFrame({
"sensor_id": ["s-01", "s-02", "s-01", "s-03"] * 1000,
"value": [23.5, 18.2, 24.1, 19.8] * 1000,
"unit": ["celsius"] * 4000,
"timestamp": pd.date_range("2025-01-01", periods=4000, freq="min")
})
# Write Parquet (columnar, compressed)
table = pa.Table.from_pandas(df)
pq.write_table(table, "measurements.parquet", compression="snappy")
# Read Parquet (can read specific columns without loading all data)
table_back = pq.read_table("measurements.parquet", columns=["sensor_id", "value"])
df_subset = table_back.to_pandas()
# R: Parquet with arrow
library(arrow)
# Write
df <- data.frame(sensor_id = rep("s-01", 1000), value = rnorm(1000))
arrow::write_parquet(df, "measurements.parquet")
# Read (with column selection — only reads selected columns from disk)
df_back <- arrow::read_parquet("measurements.parquet", col_select = c("value"))
预期结果: Parquet 文件对于典型表格数据比 CSV 小 5-20 倍。
失败处理: 如果 Arrow 不可用,使用 fastparquet(Python)或 CSV 加 gzip 作为后备。
为您的特定数据和用例运行基准测试:
import json, msgpack, time
import pyarrow as pa, pyarrow.parquet as pq
data = [{"id": i, "value": i * 0.1, "label": f"item-{i}"} for i in range(10000)]
# JSON
start = time.perf_counter()
json_bytes = json.dumps(data).encode()
json_time = time.perf_counter() - start
# MessagePack
start = time.perf_counter()
msgpack_bytes = msgpack.packb(data)
msgpack_time = time.perf_counter() - start
print(f"JSON: {len(json_bytes):>8} bytes, {json_time*1000:.1f} ms")
print(f"MsgPack: {len(msgpack_bytes):>8} bytes, {msgpack_time*1000:.1f} ms")
预期结果: 基准测试结果指导生产环境的格式选择。 失败处理: 如果任何格式的性能不足,考虑将压缩(zstd、snappy)作为正交优化手段。
!!python/object 标签执行任意代码。始终使用安全加载器。design-serialization-schema — 模式设计、版本管理和演进策略implement-pharma-serialisation — 药品序列化(不同领域,相同命名)create-quarto-report — 报告的数据输出格式化