JSON合并工具

JSON合并工具

1. 项目概述

本项目旨在开发一个强大而灵活的JSON合并工具,能够合并多个JSON文件,处理复杂的嵌套结构,提供详细的合并报告,并实现全面的验证和错误处理机制。

2. 功能需求

2.1 基本合并功能

  • 支持合并两个或多个JSON文件
  • 处理嵌套的JSON结构
  • 提供不同的合并策略选项(如覆盖、保留原值)

2.2 验证和错误处理

  • JSON结构验证
  • 数据类型一致性检查
  • 文件大小限制检查
  • 键名验证
  • 详细的错误报告
  • 警告系统
  • 错误恢复机制
  • 操作日志记录

2.3 合并报告生成

  • 生成详细的合并过程报告
  • 包含基本信息、合并统计、详细操作日志、警告和错误摘要、性能指标

2.4 多文件合并

  • 支持任意数量的输入JSON文件
  • 按指定顺序依次合并文件
  • 为每个输入文件生成单独的统计信息

3. 技术设计

3.1 合并算法

使用递归方法处理嵌套的JSON结构:

  1. 遍历第二个JSON对象的所有键值对
  2. 如果键在第一个对象中不存在,直接添加
  3. 如果键存在且值都是字典,递归合并
  4. 如果键存在且值都是列表,合并列表
  5. 如果键存在但值类型不同,根据策略处理(覆盖或保留)
  6. 如果键存在且值类型相同,根据策略更新

3.2 验证机制

  1. JSON结构验证:使用json.loads()验证JSON格式
  2. 深度检查:递归检查JSON嵌套深度,设置最大深度限制
  3. 大小检查:在读取文件前检查文件大小
  4. 类型一致性:在合并过程中检查相同键的值类型

3.3 错误处理

  1. 使用try-except块捕获并处理异常
  2. 实现自定义异常类处理特定错误
  3. 使用logging模块记录警告和错误
  4. 对于非致命错误,提供继续处理的选项

3.4 报告生成

使用MergeReport类管理报告生成:

  1. 在合并过程中记录每个操作
  2. 统计新增、更新和冲突的键数量
  3. 记录警告和错误
  4. 生成性能指标(处理时间、内存使用)
  5. 格式化输出详细的报告

3.5 多文件处理

  1. 使用列表存储多个输入文件路径
  2. 逐个处理文件,将结果合并到一个主JSON对象中
  3. 在报告中分别记录每个文件的处理情况

3.6 命令行接口

使用argparse模块处理命令行参数:

  1. 输入文件路径(支持多个)
  2. 输出文件路径
  3. 合并策略选项
  4. 报告输出路径选项

4. 实现细节

4.1 主要类和函数

  1. MergeReport 类:管理报告生成
  2. merge_json() 函数:实现JSON合并逻辑
  3. merge_json_files() 函数:处理文件I/O和调用合并函数
  4. main() 函数:处理命令行参数和orchestrate整个过程

4.2 数据结构

  • 使用Python的字典表示JSON对象
  • 使用列表存储多个输入文件路径

4.3 外部依赖

  • json:用于JSON解析和序列化
  • argparse:用于命令行参数处理
  • logging:用于日志记录
  • psutil:用于获取内存使用情况(可选)

5. 使用示例

python merge_json.py file1.json file2.json file3.json output.json --strategy overwrite --report merge_report.txt

6. 未来扩展

  1. 性能优化:实现流式处理或分块处理大文件
  2. 并行处理:使用多线程或多进程加速处理
  3. 配置文件:支持通过配置文件指定复杂的合并规则
  4. 可视化:生成合并过程的可视化表示
  5. GUI界面:开发图形用户界面,提高易用性

7. 结论

这个JSON合并工具提供了强大的功能,包括多文件合并、详细的报告生成、全面的验证和错误处理。考虑了灵活性和可扩展性,能够满足各种复杂的JSON合并需求。持续的优化和功能扩展,这个工具可以成为处理JSON数据的有力助手。

8.代码

import json
import sys
import os
import logging
import time
import argparse
from typing import Dict, Any, List

class MergeReport:
    def __init__(self):
        self.start_time = time.time()
        self.total_keys = 0
        self.new_keys = 0
        self.updated_keys = 0
        self.conflict_keys = 0
        self.warnings = []
        self.errors = []
        self.detailed_log = []
        self.file_stats = {}

    def add_operation(self, file: str, key: str, operation: str, details: str = ""):
        self.detailed_log.append(f"{file} - {key}: {operation} - {details}")
        self.total_keys += 1
        if operation == "新增":
            self.new_keys += 1
        elif operation == "更新":
            self.updated_keys += 1
        elif operation == "冲突":
            self.conflict_keys += 1
        
        if file not in self.file_stats:
            self.file_stats[file] = {"新增": 0, "更新": 0, "冲突": 0}
        self.file_stats[file][operation] += 1

    def add_warning(self, message: str):
        self.warnings.append(message)

    def add_error(self, message: str):
        self.errors.append(message)

    def generate_report(self, input_files: List[str], output_file: str, strategy: str) -> str:
        end_time = time.time()
        process_time = end_time - self.start_time

        report = f"""
合并报告
========

基本信息:
- 合并时间: {time.strftime('%Y-%m-%d %H:%M:%S')}
- 输入文件:
{chr(10).join(['  - ' + file for file in input_files])}
- 输出文件: {output_file}
- 合并策略: {strategy}

合并统计:
- 总处理键数: {self.total_keys}
- 新增键数: {self.new_keys}
- 更新键数: {self.updated_keys}
- 冲突键数: {self.conflict_keys}

文件统计:
"""
        for file, stats in self.file_stats.items():
            report += f"- {file}:\n"
            report += f"  新增: {stats['新增']}, 更新: {stats['更新']}, 冲突: {stats['冲突']}\n"

        report += f"""
详细操作日志:
{chr(10).join(self.detailed_log)}

警告:
{chr(10).join(self.warnings) if self.warnings else "无"}

错误:
{chr(10).join(self.errors) if self.errors else "无"}

性能指标:
- 处理时间: {process_time:.2f} 秒
- 峰值内存使用: {self.get_peak_memory_usage()} MB
        """
        return report

    def get_peak_memory_usage(self):
        import psutil
        process = psutil.Process(os.getpid())
        return process.memory_info().peak_wset / 1024 / 1024  # 转换为MB

def merge_json(data1: Dict[str, Any], data2: Dict[str, Any], strategy: str, report: MergeReport, file_name: str) -> Dict[str, Any]:
    result = data1.copy()
    for key, value in data2.items():
        if key in result:
            if isinstance(result[key], dict) and isinstance(value, dict):
                result[key] = merge_json(result[key], value, strategy, report, file_name)
                report.add_operation(file_name, key, "更新", "合并嵌套字典")
            elif isinstance(result[key], list) and isinstance(value, list):
                result[key] = result[key] + value
                report.add_operation(file_name, key, "更新", "合并列表")
            elif type(result[key]) != type(value):
                report.add_warning(f"类型不匹配: 文件 {file_name} 中的键 '{key}' 与现有数据类型不同")
                if strategy == 'overwrite':
                    result[key] = value
                    report.add_operation(file_name, key, "冲突", f"类型不匹配,使用新文件的值")
                else:
                    report.add_operation(file_name, key, "冲突", f"类型不匹配,保留原值")
            elif strategy == 'overwrite':
                result[key] = value
                report.add_operation(file_name, key, "更新", "覆盖现有值")
            else:
                report.add_operation(file_name, key, "保留", "保留原有值")
        else:
            result[key] = value
            report.add_operation(file_name, key, "新增", "添加新键")
    return result

def merge_json_files(input_files: List[str], output_file: str, strategy: str = 'overwrite') -> str:
    report = MergeReport()
    merged_data = {}
    try:
        for file in input_files:
            with open(file, 'r', encoding='utf-8') as f:
                data = json.load(f)
                merged_data = merge_json(merged_data, data, strategy, report, file)

        with open(output_file, 'w', encoding='utf-8') as out_file:
            json.dump(merged_data, out_file, ensure_ascii=False, indent=4)

        return report.generate_report(input_files, output_file, strategy)
    except Exception as e:
        report.add_error(f"合并过程中发生错误: {str(e)}")
        return report.generate_report(input_files, output_file, strategy)

def main():
    parser = argparse.ArgumentParser(description="合并多个JSON文件并生成报告")
    parser.add_argument('input_files', nargs='+', type=str, help="输入JSON文件的路径列表")
    parser.add_argument('output', type=str, help="输出JSON文件的路径")
    parser.add_argument('--strategy', type=str, choices=['overwrite', 'keep'], default='overwrite',
                        help="合并策略: 'overwrite' 覆盖重复键, 'keep' 保留原始值 (默认: overwrite)")
    parser.add_argument('--report', type=str, help="合并报告输出路径")

    args = parser.parse_args()

    try:
        report = merge_json_files(args.input_files, args.output, args.strategy)
        if args.report:
            with open(args.report, 'w', encoding='utf-8') as report_file:
                report_file.write(report)
            print(f"合并报告已保存到: {args.report}")
        else:
            print(report)
    except Exception as e:
        print(f"错误: {str(e)}")
        sys.exit(1)

if __name__ == "__main__":
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/882444.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue3(二)计算属性Computed,监视属性watch,watchEffect,标签的ref属性,propos属性,生命周期,自定义hook

文章目录 一 、计算属性1. 简写2. 完整写法 二、监视watch1. 监视【ref】定义的【基本类型】数据2. 监视【ref】定义的【对象类型】数据3. 监视【reactive】定义的【对象类型】数据4. 监视【ref】或【reactive】定义的【对象类型】数据中的某个属性5. 监视多个数据总结 三、wat…

html+css(如何用css做出京东页面,静态版)

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>京东</title><link rel"stylesheet&q…

基于Es和智普AI实现的语义检索

1、什么是语义检索 语义检索是一种利用自然语言处理&#xff08;NLP&#xff09;和人工智能&#xff08;AI&#xff09;技术来理解搜索查询的语义&#xff0c;以提供更准确和相关搜索结果的搜索技术&#xff0c;语义检索是一项突破性的技术&#xff0c;旨在通过深入理解单词和…

知识库管理系统的未来趋势:从单一平台到生态系统

在数字化浪潮的推动下&#xff0c;知识库管理系统&#xff08;Knowledge Base Management System, KBMS&#xff09;正逐步从传统的单一平台向更加开放、灵活、智能的生态系统转变。这一转变不仅体现了技术进步的必然结果&#xff0c;也深刻反映了市场需求的变化。本文将分析随…

neo4j节点关联路径的表示、节点的增删改查

目录 核心概念节点的增删改查&#xff08;1&#xff09;增&#xff08;2&#xff09;查&#xff08;3&#xff09;删&#xff08;4&#xff09;改 neo4j文档&#xff1a;https://neo4j.com/docs/ https://neo4j.com/docs/cypher-manual/current/introduction/ 核心概念 节点 ne…

如何将Excel表格嵌入Web网页在线预览、编辑并保存到自己服务器上?

猿大师办公助手作为一款专业级的网页编辑Office方案&#xff0c;不仅可以把微软Office、金山WPS和永中Office的Word文档内嵌到浏览器网页中实现在线预览、编辑保存等操作&#xff0c;还可以把微软Office、金山WPS和永中Office的Excel表格实现网页中在线预览、编辑并保存到服务器…

C++的哲学思想

C的哲学思想 文章目录 C的哲学思想&#x1f4a1;前言&#x1f4a1;C的哲学思想☁️C底层不应该基于任何其他语言&#xff08;汇编语言除外&#xff09;☁️只为使用的东西付费&#xff08;不需要为没有使用到的语言特性付费&#xff09;☁️以低成本提供高级抽象&#xff08;更…

在云渲染中3D工程文件安全性怎么样?

在云渲染中&#xff0c;3D工程文件的安全性是用户最关心的问题之一。随着企业对数据保护意识的增强&#xff0c;云渲染平台采取了严格的安全措施和加密技术&#xff0c;以确保用户数据的安全性和隐私性。 云渲染平台为了保障用户数据的安全&#xff0c;采取了多层次的安全措施。…

【VUE3.0】动手做一套像素风的前端UI组件库---Button

目录 引言做之前先仔细看看UI设计稿解读一下都有哪些元素&#xff1a;素材补充 代码编写1. 按钮四周边框2. 默认状态下按钮颜色立体效果3. 鼠标移入聚焦4. 模拟鼠标点击效果 组件封装1. 按类型设置颜色2. 设置按钮禁用状态3. 处理一个bug4. 看下整体组件效果5. 组件完整代码6. …

vue.js 展示一个树形结构的数据视图,并禁用其中默认选中的节点

功能描述 展示树形结构&#xff1a; 使用 Element UI 的 <el-tree> 组件展示树形结构数据。数据由 content 数组提供&#xff0c;树形结构包含了嵌套的节点及其子节点。 默认选中节点&#xff1a; 使用 defaultCheckedKeys 属性指定默认选中的节点。这些节点在树形结构渲…

求职Leetcode题目(11)

1.最长连续序列 解题思路: 方法一&#xff1a; • 首先对数组进行排序&#xff0c;这样我们可以直接比较相邻的元素是否连续。• 使用一个变量 cur_cnt 来记录当前的连续序列长度。• 遍历排序后的数组&#xff1a; 如果当前元素与前一个元素相等&#xff0c;则跳过&#xf…

Debian安装mysql遇到的问题解决及yum源配置

文章目录 一、安装mysql遇到的问题解决二、Debain系统mysql8.0的安装以及远程连接三、彻底卸载软件四、Python 操作 mysql五、debian软件源source.list文件格式说明1. 第一部分2. 第二部分3. 第三部分4. 第四部分5. 关于源的混用问题6. 按需修改自己的sources.list7. 更新软件包…

python爬虫案例——腾讯网新闻标题(异步加载网站数据抓取,post请求)(6)

文章目录 前言1、任务目标2、抓取流程2.1 分析网页2.2 编写代码2.3 思路分析前言 本篇案例主要讲解异步加载网站如何分析网页接口,以及如何观察post请求URL的参数,网站数据并不难抓取,主要是将要抓取的数据接口分析清楚,才能根据需求编写想要的代码。 1、任务目标 目标网…

LabVIEW提高开发效率技巧----使用LabVIEW工具

LabVIEW为开发者提供了多种工具和功能&#xff0c;不仅提高工作效率&#xff0c;还能确保项目的质量和可维护性。以下详细介绍几种关键工具&#xff0c;并结合实际案例说明它们的应用。 1. VI Analyzer&#xff1a;自动检查代码质量 VI Analyzer 是LabVIEW提供的一款强大的工…

Java — LeetCode 面试经典150题(一)

双指针 125.验证回文串 题目 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&#xff0c;如果它是 回文串 &#xff0c;返回…

验收测试:从需求到交付的全程把控!

在软件开发过程中&#xff0c;验收测试是一个至关重要的环节。它不仅是对软件质量的把关&#xff0c;也是对整个项目周期的全程把控。从需求分析到最终的软件交付&#xff0c;验收测试都需要严格进行&#xff0c;以确保软件能够符合预期的质量和性能要求。 一、需求分析阶段 在…

0-1开发自己的obsidian plugin DAY 1

官网教程有点mismatch&#xff0c;而且从0-100跨度较大&#xff0c;&#x1f4dd;记录一下自己的踩坑过程 首先&#xff0c;官网给的example里只有main.ts&#xff0c;需要自己编译成main.js 在视频教程&#xff08;https://www.youtube.com/watch?v9lA-jaMNS0k&#xff09;里…

K8S服务发布

一 、服务发布方式对比 二者主要区别在于&#xff1a; 1. 部署复杂性&#xff1a;传统的服务发布方式通常涉及手动配置 和管理服务器、网络设置、负载均衡等&#xff0c;过程相对复 杂且容易出错。相比之下&#xff0c;Kubernetes服务发布方式 通过使用容器编排和自动化部署工…

大数据新视界 --大数据大厂之 Reactjs 在大数据应用开发中的优势与实践

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

虚幻引擎的射线检测/射线追踪

射线检测在 FPS/TPS 游戏中被广泛应用 什么是射线检测? 两个点行成一条线 , 射线检测是从一个起始点发出一条到终点的射线 , 如果射线命中一个游戏对象&#xff0c;就可以获取到对象命中时的 位置、距离、角度、是否命中、骨骼 等非常多的信息 , 这些信息在射击游戏中至关重…