在数据处理和交换中,JSON和CSV是两种最常用的数据格式。理解它们的差异以及如何在两者之间转换,是每个开发者和数据分析师的必备技能。本指南将全面介绍JSON与CSV转换的所有知识。

目录

核心要点

  • 结构差异:JSON支持嵌套和复杂数据结构;CSV是扁平的二维表格格式。
  • 数据类型:JSON保留数据类型(字符串、数字、布尔值);CSV中所有数据都是字符串。
  • 可读性:CSV更适合表格数据展示;JSON更适合层次化数据。
  • 文件大小:CSV通常比等效JSON文件更小。
  • 兼容性:CSV可直接在Excel中打开;JSON需要专门的解析器。
  • 转换挑战:嵌套JSON转CSV需要扁平化处理,可能丢失结构信息。

需要快速转换JSON和CSV?试试我们的免费在线工具,支持复杂嵌套结构处理。

立即转换 - 免费在线JSON转CSV工具

JSON和CSV格式简介

什么是JSON?

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,基于JavaScript对象语法,但独立于任何编程语言。

JSON示例:

{
  "name": "张三",
  "age": 28,
  "email": "zhangsan@example.com",
  "skills": ["JavaScript", "Python", "Go"],
  "address": {
    "city": "北京",
    "district": "朝阳区"
  }
}

JSON特点:

  • 支持嵌套对象和数组
  • 保留数据类型(字符串、数字、布尔值、null)
  • 键值对结构
  • 广泛用于API数据交换

什么是CSV?

CSV(Comma-Separated Values)是一种简单的表格数据格式,使用逗号分隔字段,换行符分隔记录。

CSV示例:

name,age,email,city
张三,28,zhangsan@example.com,北京
李四,32,lisi@example.com,上海
王五,25,wangwu@example.com,广州

CSV特点:

  • 扁平的二维表格结构
  • 所有数据都是纯文本
  • 可直接在电子表格软件中打开
  • 文件体积小,易于传输

JSON与CSV的核心差异

特性 JSON CSV
数据结构 层次化、支持嵌套 扁平的二维表格
数据类型 字符串、数字、布尔值、null、对象、数组 仅字符串
可读性 结构清晰,但较冗长 简洁,表格形式直观
文件大小 相对较大(包含键名) 较小(仅数据和分隔符)
解析复杂度 需要JSON解析器 简单文本处理即可
软件兼容性 需要专门工具 Excel、Google Sheets直接支持
适用场景 API、配置文件、复杂数据 数据导出、报表、批量处理

JSON转CSV的原理

将JSON转换为CSV的核心挑战是处理JSON的层次结构,因为CSV只支持二维表格。

扁平化处理

嵌套对象需要通过路径拼接转换为扁平键名:

原始JSON:

{
  "user": {
    "name": "张三",
    "contact": {
      "email": "zhangsan@example.com",
      "phone": "13800138000"
    }
  }
}

扁平化后:

{
  "user.name": "张三",
  "user.contact.email": "zhangsan@example.com",
  "user.contact.phone": "13800138000"
}

转换为CSV:

user.name,user.contact.email,user.contact.phone
张三,zhangsan@example.com,13800138000

数组处理策略

数组是JSON转CSV中最复杂的部分,常见处理策略包括:

策略1:数组索引展开

{"tags": ["前端", "后端", "全栈"]}

转换为:

tags.0,tags.1,tags.2
前端,后端,全栈

策略2:数组合并为字符串

tags
"前端,后端,全栈"

策略3:数组展开为多行

tags
前端
后端
全栈

CSV转JSON的原理

CSV转JSON相对简单,主要步骤:

  1. 解析表头:第一行作为JSON对象的键名
  2. 解析数据行:每行转换为一个JSON对象
  3. 类型推断:尝试将字符串转换为适当的数据类型
  4. 结构重建:根据键名中的分隔符重建嵌套结构

CSV输入:

name,age,city,active
张三,28,北京,true
李四,32,上海,false

JSON输出:

[
  {"name": "张三", "age": 28, "city": "北京", "active": true},
  {"name": "李四", "age": 32, "city": "上海", "active": false}
]

需要将CSV转换为JSON?使用我们的在线工具:

立即转换 - 免费在线CSV转JSON工具

代码示例

JavaScript

// JSON转CSV
function jsonToCsv(jsonData) {
  if (!Array.isArray(jsonData) || jsonData.length === 0) {
    return '';
  }
  
  const flattenObject = (obj, prefix = '') => {
    return Object.keys(obj).reduce((acc, key) => {
      const newKey = prefix ? `${prefix}.${key}` : key;
      if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
        Object.assign(acc, flattenObject(obj[key], newKey));
      } else if (Array.isArray(obj[key])) {
        acc[newKey] = obj[key].join(';');
      } else {
        acc[newKey] = obj[key];
      }
      return acc;
    }, {});
  };
  
  const flatData = jsonData.map(item => flattenObject(item));
  const headers = [...new Set(flatData.flatMap(Object.keys))];
  
  const csvRows = [
    headers.join(','),
    ...flatData.map(row => 
      headers.map(header => {
        const value = row[header] ?? '';
        return typeof value === 'string' && value.includes(',') 
          ? `"${value}"` 
          : value;
      }).join(',')
    )
  ];
  
  return csvRows.join('\n');
}

// CSV转JSON
function csvToJson(csvString) {
  const lines = csvString.trim().split('\n');
  const headers = lines[0].split(',').map(h => h.trim());
  
  return lines.slice(1).map(line => {
    const values = line.split(',');
    return headers.reduce((obj, header, index) => {
      let value = values[index]?.trim() ?? '';
      
      if (value === 'true') value = true;
      else if (value === 'false') value = false;
      else if (value !== '' && !isNaN(value)) value = Number(value);
      
      obj[header] = value;
      return obj;
    }, {});
  });
}

// 使用示例
const users = [
  { name: '张三', age: 28, city: '北京' },
  { name: '李四', age: 32, city: '上海' }
];

const csv = jsonToCsv(users);
console.log(csv);
// name,age,city
// 张三,28,北京
// 李四,32,上海

const json = csvToJson(csv);
console.log(json);

Python

import csv
import json
from io import StringIO
from typing import Any

def flatten_dict(d: dict, parent_key: str = '', sep: str = '.') -> dict:
    """扁平化嵌套字典"""
    items = []
    for k, v in d.items():
        new_key = f"{parent_key}{sep}{k}" if parent_key else k
        if isinstance(v, dict):
            items.extend(flatten_dict(v, new_key, sep).items())
        elif isinstance(v, list):
            items.append((new_key, ';'.join(str(i) for i in v)))
        else:
            items.append((new_key, v))
    return dict(items)

def json_to_csv(json_data: list[dict]) -> str:
    """将JSON数组转换为CSV字符串"""
    if not json_data:
        return ''
    
    flat_data = [flatten_dict(item) for item in json_data]
    all_keys = set()
    for item in flat_data:
        all_keys.update(item.keys())
    headers = sorted(all_keys)
    
    output = StringIO()
    writer = csv.DictWriter(output, fieldnames=headers)
    writer.writeheader()
    writer.writerows(flat_data)
    
    return output.getvalue()

def csv_to_json(csv_string: str) -> list[dict]:
    """将CSV字符串转换为JSON数组"""
    reader = csv.DictReader(StringIO(csv_string))
    result = []
    
    for row in reader:
        parsed_row = {}
        for key, value in row.items():
            if value.lower() == 'true':
                parsed_row[key] = True
            elif value.lower() == 'false':
                parsed_row[key] = False
            elif value.isdigit():
                parsed_row[key] = int(value)
            else:
                try:
                    parsed_row[key] = float(value)
                except ValueError:
                    parsed_row[key] = value
        result.append(parsed_row)
    
    return result

# 使用示例
users = [
    {"name": "张三", "age": 28, "address": {"city": "北京", "district": "朝阳区"}},
    {"name": "李四", "age": 32, "address": {"city": "上海", "district": "浦东新区"}}
]

csv_output = json_to_csv(users)
print(csv_output)

json_output = csv_to_json(csv_output)
print(json.dumps(json_output, ensure_ascii=False, indent=2))

Go

package main

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

func flattenMap(data map[string]interface{}, prefix string, result map[string]string) {
	for key, value := range data {
		newKey := key
		if prefix != "" {
			newKey = prefix + "." + key
		}

		switch v := value.(type) {
		case map[string]interface{}:
			flattenMap(v, newKey, result)
		case []interface{}:
			var strValues []string
			for _, item := range v {
				strValues = append(strValues, fmt.Sprintf("%v", item))
			}
			result[newKey] = strings.Join(strValues, ";")
		default:
			result[newKey] = fmt.Sprintf("%v", v)
		}
	}
}

func jsonToCSV(jsonData []map[string]interface{}) string {
	if len(jsonData) == 0 {
		return ""
	}

	var flatData []map[string]string
	headerSet := make(map[string]bool)

	for _, item := range jsonData {
		flat := make(map[string]string)
		flattenMap(item, "", flat)
		flatData = append(flatData, flat)
		for k := range flat {
			headerSet[k] = true
		}
	}

	var headers []string
	for k := range headerSet {
		headers = append(headers, k)
	}

	var sb strings.Builder
	writer := csv.NewWriter(&sb)
	writer.Write(headers)

	for _, row := range flatData {
		var values []string
		for _, h := range headers {
			values = append(values, row[h])
		}
		writer.Write(values)
	}
	writer.Flush()

	return sb.String()
}

func csvToJSON(csvData string) ([]map[string]interface{}, error) {
	reader := csv.NewReader(strings.NewReader(csvData))
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	if len(records) < 2 {
		return []map[string]interface{}{}, nil
	}

	headers := records[0]
	var result []map[string]interface{}

	for _, row := range records[1:] {
		item := make(map[string]interface{})
		for i, value := range row {
			if i < len(headers) {
				if num, err := strconv.ParseFloat(value, 64); err == nil {
					item[headers[i]] = num
				} else if value == "true" {
					item[headers[i]] = true
				} else if value == "false" {
					item[headers[i]] = false
				} else {
					item[headers[i]] = value
				}
			}
		}
		result = append(result, item)
	}

	return result, nil
}

func main() {
	jsonStr := `[
		{"name": "张三", "age": 28, "city": "北京"},
		{"name": "李四", "age": 32, "city": "上海"}
	]`

	var data []map[string]interface{}
	json.Unmarshal([]byte(jsonStr), &data)

	csvOutput := jsonToCSV(data)
	fmt.Println("CSV输出:")
	fmt.Println(csvOutput)

	jsonOutput, _ := csvToJSON(csvOutput)
	jsonBytes, _ := json.MarshalIndent(jsonOutput, "", "  ")
	fmt.Println("JSON输出:")
	fmt.Println(string(jsonBytes))
}

最佳实践

1. 选择正确的转换方向

场景 推荐格式
API数据交换 JSON
数据导出到Excel CSV
配置文件 JSON
批量数据导入 CSV
复杂嵌套数据 JSON
简单表格数据 CSV

2. 处理特殊字符

// CSV中处理包含逗号、引号、换行的值
function escapeCSVValue(value) {
  if (typeof value !== 'string') return value;
  
  if (value.includes(',') || value.includes('"') || value.includes('\n')) {
    return `"${value.replace(/"/g, '""')}"`;
  }
  return value;
}

3. 编码处理

  • UTF-8 BOM:导出CSV供Excel打开时,添加BOM(\uFEFF)确保中文正确显示
  • 字符转义:正确处理引号和换行符
// 添加BOM以支持Excel正确显示中文
const csvWithBOM = '\uFEFF' + csvContent;

4. 大数据处理

  • 流式处理:处理大文件时使用流式读写,避免内存溢出
  • 分批处理:将大数据集分批转换
  • 进度反馈:长时间操作时提供进度指示

5. 数据验证

// 转换前验证JSON结构
function validateJsonForCsv(data) {
  if (!Array.isArray(data)) {
    throw new Error('JSON数据必须是数组');
  }
  
  if (data.length === 0) {
    throw new Error('JSON数组不能为空');
  }
  
  const firstKeys = Object.keys(data[0]).sort().join(',');
  for (let i = 1; i < data.length; i++) {
    const keys = Object.keys(data[i]).sort().join(',');
    if (keys !== firstKeys) {
      console.warn(`第${i+1}行的结构与第一行不一致`);
    }
  }
  
  return true;
}

常见使用场景

  1. 数据导出

    • 将数据库查询结果导出为CSV供业务人员分析
    • 生成报表供Excel处理
  2. 数据导入

    • 将Excel数据转换为JSON供API使用
    • 批量导入用户数据
  3. 数据迁移

    • 不同系统间的数据格式转换
    • 遗留系统数据迁移
  4. 数据分析

    • 将JSON日志转换为CSV进行统计分析
    • 准备机器学习训练数据
  5. API集成

    • 第三方服务数据格式适配
    • 多系统数据同步

常见问题

JSON转CSV会丢失数据吗?

转换过程中可能丢失以下信息:

  • 数据类型:所有数据变为字符串
  • 嵌套结构:被扁平化处理
  • 数组顺序:某些处理方式可能改变顺序

建议保留原始JSON作为备份。

如何处理嵌套很深的JSON?

对于深度嵌套的JSON,建议:

  1. 使用点号路径表示法(如 user.address.city
  2. 考虑是否真的需要所有嵌套数据
  3. 可能需要多个CSV文件表示不同层级

CSV中的中文乱码怎么解决?

确保:

  1. 文件使用UTF-8编码保存
  2. 导出时添加BOM标记
  3. Excel打开时选择正确的编码

如何不写代码转换JSON和CSV?

使用在线工具是最快捷的方式:

大文件转换有什么建议?

  • 使用流式处理避免内存问题
  • 考虑分批处理
  • 使用命令行工具如 jq 配合 csvkit

总结

JSON和CSV各有优势,选择哪种格式取决于具体使用场景:

选择JSON当:

  • 数据有复杂嵌套结构
  • 需要保留数据类型
  • 用于API数据交换
  • 需要灵活的数据结构

选择CSV当:

  • 数据是简单的表格形式
  • 需要在Excel中处理
  • 文件大小是考虑因素
  • 需要人工可读性

快速总结:

  • JSON支持复杂结构,CSV是扁平表格
  • 转换时注意数据类型和嵌套处理
  • 特殊字符需要正确转义
  • 中文数据注意编码问题

准备好转换数据了吗?试试我们的免费在线工具:

JSON转CSV - 免费在线转换工具

CSV转JSON - 免费在线转换工具