返回

Excel 工作簿差异比较

数据互转

正在载入

正在加载工具

工具代码会在打开时按需载入,请稍候。

本工具的全部运算都发生在你的浏览器中,输入内容不会发送到任何服务器。

关于这个工具

比较两个已保存的 XLSX 工作簿,不上传内容,也不修改源文件。默认整本比较按完全相同的工作表名称配对,再按单元格坐标比较;也可明确选择左右各一张表,按一个或多个键列匹配行。报告分别呈现值、类型、公式文本、公式的已存缓存结果、数字格式以及工作簿和工作表元数据。精确比较保留数字的原始存储文本,并区分缺少单元格与显式空白。筛选并分页检查差异后,可导出所有符合筛选条件的类型化 JSON 或带安全标签的 CSV。ExcelJS 4.4.0 与本地 XML 防护在浏览器工作线程运行,不执行公式、宏或外部数据连接。

常见用途

  • 在分发新版预算或业务报表前,检查输入值、公式以及可能已过期的公式缓存结果发生了什么变化。
  • 以唯一且保留类型的 ID 或复合键对照已重新排序的库存、订单行,区分文本 001 与数字 1,并保留两侧源坐标。
  • 在工作簿交接时同时检查单元格变化与工作表增删、顺序、可见性、合并范围、声明范围和列元数据。

使用方法

  1. 1.选择修改前与修改后的两个 .xlsx 文件,每个不超过 16 MiB,然后读取两侧。查看工作表与日期系统。请使用已保存、未加密的 XLSX 副本;更改 XLS、XLSB 或 XLSM 的后缀并不能转换格式。
  2. 2.保留整本坐标模式可自动配对名称完全相同的工作表。需要比较改名表时,明确选择左右各一张表。在所选表对中使用坐标模式,或输入最多八个互不重复的键列字母,例如 A,C。键模式要求表头行号为 1 至 1048575,仅处理该行之后实际包含单元格的行。
  3. 3.开始比较,同时检查结构事件与单元格变化。键模式要求每个键分量存在、非空、非公式,并且两侧各自的带类型复合键唯一。遇到无效键时,请在单独副本中修正或选择合适的键,不要猜测记录对应关系。 选择结果筛选条件,每页浏览 25 条事件。类型化 JSON 预览可能在 600 字符处缩短;导出包含所有符合筛选条件的完整值,不局限于当前页。结构化交换选 JSON,电子表格检查可选强制带安全标签的 CSV。清空或更换文件会丢弃当前会话。

可执行的工作簿快照比较示例

保留精确的原始数字文本

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "1"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "1.0"
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1
  },
  "changes": [
    {
      "kind": "cell",
      "status": "changed",
      "field": "cell",
      "leftAddress": "A1",
      "rightAddress": "A1",
      "before": {
        "type": "number",
        "value": "1",
        "formula": null,
        "cached": null,
        "numberFormat": null
      },
      "after": {
        "type": "number",
        "value": "1.0",
        "formula": null,
        "cached": null,
        "numberFormat": null
      }
    }
  ]
}

这些可执行示例描述小型合成 XLSX 的文件内容,不是可粘贴到工具中的 JSON。省略设置时使用整本坐标模式。构建检查写出真实 OOXML 文件、解析并核对展示的报告摘录;实际导出还包含工作表、键和选项上下文。两侧数字都表示一,但 XML 文本从 1 变为 1.0。比较会报告这个精确变化,不舍入,也不使用误差阈值。

文本标识符不同于数字

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "001"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "1"
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1
  },
  "changes": [
    {
      "kind": "cell",
      "status": "changed",
      "field": "cell",
      "leftAddress": "A1",
      "rightAddress": "A1",
      "before": {
        "type": "string",
        "value": "001",
        "formula": null,
        "cached": null,
        "numberFormat": null
      },
      "after": {
        "type": "number",
        "value": "1",
        "formula": null,
        "cached": null,
        "numberFormat": null
      }
    }
  ]
}

文本 001 变为数字 1,单元格类型与存储值都发生变化。前导零不会被悄悄转换。

缺少单元格与显式空白

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "B1",
            "type": "string",
            "value": "keep"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "blank",
            "value": null
          },
          {
            "address": "B1",
            "type": "string",
            "value": "keep"
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 1,
    "removed": 0,
    "changed": 0
  },
  "changes": [
    {
      "kind": "cell",
      "status": "added",
      "field": "cell",
      "leftAddress": null,
      "rightAddress": "A1",
      "before": null,
      "after": {
        "type": "blank",
        "value": null,
        "formula": null,
        "cached": null,
        "numberFormat": null
      }
    }
  ]
}

B1 在两侧都存在,因此行是否存在没有变化。修改前没有 A1,修改后有显式空白 A1,所以报告一个新增单元格。

空白与空文本

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "blank",
            "value": null
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": ""
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1
  },
  "changes": [
    {
      "kind": "cell",
      "status": "changed",
      "field": "cell",
      "leftAddress": "A1",
      "rightAddress": "A1",
      "before": {
        "type": "blank",
        "value": null,
        "formula": null,
        "cached": null,
        "numberFormat": null
      },
      "after": {
        "type": "string",
        "value": "",
        "formula": null,
        "cached": null,
        "numberFormat": null
      }
    }
  ]
}

已经存在的空白 A1 变为已经存在的空字符串。两侧都不是缺少单元格,类型差异会保留。

公式改变,缓存结果相同

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "2",
            "formula": "1+1"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "2",
            "formula": "2*1"
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1
  },
  "changes": [
    {
      "kind": "cell",
      "status": "changed",
      "field": "cell",
      "leftAddress": "A1",
      "rightAddress": "A1",
      "before": {
        "type": "number",
        "value": "2",
        "formula": "1+1",
        "cached": {
          "type": "number",
          "value": "2"
        },
        "numberFormat": null
      },
      "after": {
        "type": "number",
        "value": "2",
        "formula": "2*1",
        "cached": {
          "type": "number",
          "value": "2"
        },
        "numberFormat": null
      }
    }
  ]
}

公式从 1+1 变为 2*1,两侧缓存都为数字 2。比较公式文本,不执行任一表达式。

公式相同,缓存变化

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "2",
            "formula": "1+1"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "3",
            "formula": "1+1"
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1
  },
  "changes": [
    {
      "kind": "cell",
      "status": "changed",
      "field": "cell",
      "leftAddress": "A1",
      "rightAddress": "A1",
      "before": {
        "type": "number",
        "value": "2",
        "formula": "1+1",
        "cached": {
          "type": "number",
          "value": "2"
        },
        "numberFormat": null
      },
      "after": {
        "type": "number",
        "value": "3",
        "formula": "1+1",
        "cached": {
          "type": "number",
          "value": "3"
        },
        "numberFormat": null
      }
    }
  ]
}

两侧公式都为 1+1,但缓存从 2 变为 3。这个故意不一致的合成样例证明工具报告已存缓存,而不是重新计算。

仅数字格式变化

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "1",
            "numberFormat": "0.0"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "number",
            "value": "1",
            "numberFormat": "0.00"
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1
  },
  "changes": [
    {
      "kind": "cell",
      "status": "changed",
      "field": "cell",
      "leftAddress": "A1",
      "rightAddress": "A1",
      "before": {
        "type": "number",
        "value": "1",
        "formula": null,
        "cached": null,
        "numberFormat": "0.0"
      },
      "after": {
        "type": "number",
        "value": "1",
        "formula": null,
        "cached": null,
        "numberFormat": "0.00"
      }
    }
  ]
}

存储数字仍为 1,数字格式从 0.0 变为 0.00。即使数值未变,格式差异仍会报告。

坐标模式中的单元格移动

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A2",
            "type": "string",
            "value": "keep"
          },
          {
            "address": "B2",
            "type": "string",
            "value": "move"
          },
          {
            "address": "A3",
            "type": "string",
            "value": "keep"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A2",
            "type": "string",
            "value": "keep"
          },
          {
            "address": "A3",
            "type": "string",
            "value": "keep"
          },
          {
            "address": "B3",
            "type": "string",
            "value": "move"
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 1,
    "removed": 1,
    "changed": 0
  },
  "changes": [
    {
      "kind": "cell",
      "status": "removed",
      "field": "cell",
      "leftAddress": "B2",
      "rightAddress": null,
      "before": {
        "type": "string",
        "value": "move",
        "formula": null,
        "cached": null,
        "numberFormat": null
      },
      "after": null
    },
    {
      "kind": "cell",
      "status": "added",
      "field": "cell",
      "leftAddress": null,
      "rightAddress": "B3",
      "before": null,
      "after": {
        "type": "string",
        "value": "move",
        "formula": null,
        "cached": null,
        "numberFormat": null
      }
    }
  ]
}

字符串 move 从 B2 移到 B3。固定坐标比较产生一次移除与一次新增,不推断行插入或区域移动。

复合键忽略行顺序

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "id"
          },
          {
            "address": "B1",
            "type": "string",
            "value": "quantity"
          },
          {
            "address": "C1",
            "type": "string",
            "value": "color"
          },
          {
            "address": "A2",
            "type": "string",
            "value": "001"
          },
          {
            "address": "B2",
            "type": "number",
            "value": "5"
          },
          {
            "address": "C2",
            "type": "string",
            "value": "red"
          },
          {
            "address": "A3",
            "type": "string",
            "value": "001"
          },
          {
            "address": "B3",
            "type": "number",
            "value": "8"
          },
          {
            "address": "C3",
            "type": "string",
            "value": "blue"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "id"
          },
          {
            "address": "B1",
            "type": "string",
            "value": "quantity"
          },
          {
            "address": "C1",
            "type": "string",
            "value": "color"
          },
          {
            "address": "A2",
            "type": "string",
            "value": "001"
          },
          {
            "address": "B2",
            "type": "number",
            "value": "8"
          },
          {
            "address": "C2",
            "type": "string",
            "value": "blue"
          },
          {
            "address": "A4",
            "type": "string",
            "value": "001"
          },
          {
            "address": "B4",
            "type": "number",
            "value": "5"
          },
          {
            "address": "C4",
            "type": "string",
            "value": "red"
          }
        ]
      }
    ]
  },
  "options": {
    "scope": "pair",
    "leftSheet": "Data",
    "rightSheet": "Data",
    "mode": "keys",
    "keyColumns": "A,C",
    "headerRow": 1
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 0
  },
  "changes": []
}

A 列单独看是重复的,但带类型的 A,C 元组区分 red 和 blue。两条记录更换了物理行位置,值没有变化。键模式不会发出行是否存在的事件。

键匹配保留两侧地址

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "id"
          },
          {
            "address": "B1",
            "type": "string",
            "value": "quantity"
          },
          {
            "address": "C1",
            "type": "string",
            "value": "color"
          },
          {
            "address": "A2",
            "type": "string",
            "value": "001"
          },
          {
            "address": "B2",
            "type": "number",
            "value": "5"
          },
          {
            "address": "C2",
            "type": "string",
            "value": "red"
          },
          {
            "address": "A3",
            "type": "string",
            "value": "001"
          },
          {
            "address": "B3",
            "type": "number",
            "value": "8"
          },
          {
            "address": "C3",
            "type": "string",
            "value": "blue"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "id"
          },
          {
            "address": "B1",
            "type": "string",
            "value": "quantity"
          },
          {
            "address": "C1",
            "type": "string",
            "value": "color"
          },
          {
            "address": "A2",
            "type": "string",
            "value": "001"
          },
          {
            "address": "B2",
            "type": "number",
            "value": "8"
          },
          {
            "address": "C2",
            "type": "string",
            "value": "blue"
          },
          {
            "address": "A4",
            "type": "string",
            "value": "001"
          },
          {
            "address": "B4",
            "type": "number",
            "value": "6"
          },
          {
            "address": "C4",
            "type": "string",
            "value": "red"
          }
        ]
      }
    ]
  },
  "options": {
    "scope": "pair",
    "leftSheet": "Data",
    "rightSheet": "Data",
    "mode": "keys",
    "keyColumns": "A,C",
    "headerRow": 1
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1
  },
  "changes": [
    {
      "kind": "cell",
      "status": "changed",
      "field": "cell",
      "leftAddress": "B2",
      "rightAddress": "B4",
      "before": {
        "type": "number",
        "value": "5",
        "formula": null,
        "cached": null,
        "numberFormat": null
      },
      "after": {
        "type": "number",
        "value": "6",
        "formula": null,
        "cached": null,
        "numberFormat": null
      }
    }
  ]
}

red 记录从第 2 行移到第 4 行,数量从 5 变为 6。未变的复合键对应两侧记录,变化单元格保留 B2 与 B4。

拒绝无法唯一对应的重复键

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A2",
            "type": "string",
            "value": "001"
          },
          {
            "address": "A3",
            "type": "string",
            "value": "001"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A2",
            "type": "string",
            "value": "001"
          }
        ]
      }
    ]
  },
  "options": {
    "scope": "pair",
    "leftSheet": "Data",
    "rightSheet": "Data",
    "mode": "keys",
    "keyColumns": "A",
    "headerRow": 1
  }
}
{
  "error": "duplicateKeys"
}

修改前工作簿有两个相同的文本键 001。比较返回 duplicateKeys,不擅自保留首个或末个匹配。

公式单元格不能作为行键

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A2",
            "type": "number",
            "value": "1",
            "formula": "1+0"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A2",
            "type": "string",
            "value": "001"
          }
        ]
      }
    ]
  },
  "options": {
    "scope": "pair",
    "leftSheet": "Data",
    "rightSheet": "Data",
    "mode": "keys",
    "keyColumns": "A",
    "headerRow": 1
  }
}
{
  "error": "keyFormula"
}

A2 包含公式,缓存结果为数字 1。即使缓存看起来可用作标识符,公式也不是合格的键。

不猜测工作表改名

{
  "left": {
    "sheets": [
      {
        "name": "Old",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "same"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "New",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "same"
          }
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 2,
    "removed": 2,
    "changed": 0
  },
  "changes": [
    {
      "kind": "sheet",
      "status": "removed",
      "field": "sheet",
      "before": {
        "name": "Old",
        "index": 0,
        "state": "visible",
        "dimension": null,
        "rows": [
          1
        ],
        "columns": [],
        "merges": []
      },
      "after": null
    },
    {
      "kind": "cell",
      "status": "removed",
      "field": "cell",
      "leftAddress": "A1",
      "rightAddress": null,
      "before": {
        "type": "string",
        "value": "same",
        "formula": null,
        "cached": null,
        "numberFormat": null
      },
      "after": null
    },
    {
      "kind": "sheet",
      "status": "added",
      "field": "sheet",
      "before": null,
      "after": {
        "name": "New",
        "index": 0,
        "state": "visible",
        "dimension": null,
        "rows": [
          1
        ],
        "columns": [],
        "merges": []
      }
    },
    {
      "kind": "cell",
      "status": "added",
      "field": "cell",
      "leftAddress": null,
      "rightAddress": "A1",
      "before": null,
      "after": {
        "type": "string",
        "value": "same",
        "formula": null,
        "cached": null,
        "numberFormat": null
      }
    }
  ]
}

Old 与 New 内容相同,但整本模式只配对完全相同的名称。报告工作表删除、新增,以及旧 A1 与新 A1 的事件。

明确配对改名工作表

{
  "left": {
    "sheets": [
      {
        "name": "Old",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "same"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "New",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "same"
          }
        ]
      }
    ]
  },
  "options": {
    "scope": "pair",
    "leftSheet": "Old",
    "rightSheet": "New",
    "mode": "coordinates",
    "keyColumns": "A",
    "headerRow": 1
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1
  },
  "changes": [
    {
      "kind": "structure",
      "status": "changed",
      "field": "name",
      "before": "Old",
      "after": "New"
    }
  ]
}

选择 Old 与 New 为表对后,A1 内容相同,因此只报告表名变化。工具不会因为相似而自动建立这种配对。

保留序列 60 与日期系统

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "date",
            "value": "60",
            "numberFormat": "yyyy-mm-dd"
          }
        ]
      }
    ],
    "dateSystem": "1900"
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "date",
            "value": "60",
            "numberFormat": "yyyy-mm-dd"
          }
        ]
      }
    ],
    "dateSystem": "1904"
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 2
  },
  "changes": [
    {
      "kind": "structure",
      "status": "changed",
      "field": "dateSystem",
      "before": "1900",
      "after": "1904"
    },
    {
      "kind": "cell",
      "status": "changed",
      "field": "cell",
      "leftAddress": "A1",
      "rightAddress": "A1",
      "before": {
        "type": "date",
        "value": "60",
        "formula": null,
        "cached": null,
        "numberFormat": "yyyy-mm-dd",
        "dateSystem": "1900"
      },
      "after": {
        "type": "date",
        "value": "60",
        "formula": null,
        "cached": null,
        "numberFormat": "yyyy-mm-dd",
        "dateSystem": "1904"
      }
    }
  ]
}

序列文本与格式不变,但工作簿从 1900 系统变为 1904。元数据和日期单元格的上下文都变化,不把序列转换为日历字符串。

分别检查结构元数据

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "same"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "same"
          }
        ],
        "state": "hidden",
        "dimension": "A1:C3",
        "columns": [
          {
            "min": 1,
            "max": 2,
            "width": "12.5",
            "hidden": true
          }
        ],
        "merges": [
          "A1:B1"
        ]
      }
    ]
  }
}
{
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 4
  },
  "changes": [
    {
      "kind": "structure",
      "status": "changed",
      "field": "state",
      "before": "visible",
      "after": "hidden"
    },
    {
      "kind": "structure",
      "status": "changed",
      "field": "dimension",
      "before": null,
      "after": "A1:C3"
    },
    {
      "kind": "structure",
      "status": "changed",
      "field": "columns",
      "before": [],
      "after": [
        {
          "min": 1,
          "max": 2,
          "width": "12.5",
          "hidden": true
        }
      ]
    },
    {
      "kind": "structure",
      "status": "changed",
      "field": "merges",
      "before": [],
      "after": [
        "A1:B1"
      ]
    }
  ]
}

可见性、声明范围、列宽与隐藏区间、合并范围改变,A1 值不变。声明范围或合并范围不会生成额外单元格值。

公式风格文本保留在报告标签之后

{
  "left": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "old"
          }
        ]
      }
    ]
  },
  "right": {
    "sheets": [
      {
        "name": "Data",
        "cells": [
          {
            "address": "A1",
            "type": "string",
            "value": "=SUM(1,2)"
          }
        ]
      }
    ]
  },
  "format": "csv",
  "filter": {
    "sheet": "",
    "status": "changed"
  }
}
{
  "csvRecords": [
    [
      "id",
      "kind",
      "status",
      "leftSheet",
      "rightSheet",
      "leftAddress",
      "rightAddress",
      "key",
      "field",
      "before",
      "after"
    ],
    [
      "text:1",
      "text:cell",
      "text:changed",
      "text:Data",
      "text:Data",
      "text:A1",
      "text:A1",
      "null:",
      "text:cell",
      "json:{\"type\":\"string\",\"value\":\"old\",\"formula\":null,\"cached\":null,\"numberFormat\":null}",
      "json:{\"type\":\"string\",\"value\":\"=SUM(1,2)\",\"formula\":null,\"cached\":null,\"numberFormat\":null}"
    ]
  ]
}

输出展示的是 CSV 解析后的记录。固定表头之后,每个数据字段都带 text:、null: 或 json: 标签。不可信的 =SUM(1,2) 保留在 JSON 字符串中,不直接成为开头的电子表格公式。

工作簿比较常见误区

  • 以为相近的工作表名称或重排后的列会自动对应。
  • 用不唯一的业务名称作为行键,或忘记公式单元格不能作为键。
  • 选错表头行,导致键模式排除了本应参与的数据。
  • 把缺少单元格、显式空白和空字符串当成同一状态。
  • 把外观相同的数字、日期或公式缓存当成存储内容完全相同的证据。
  • 把结构元数据理解为自动推断出的插入、删除或格式修改过程。
  • 下载全部差异前忘记清除已有筛选。
  • 去除 CSV 安全标签,或以为报告可以直接作为工作簿补丁。

限制与说明

  • 仅接受支持范围内、未加密的 OOXML .xlsx 工作簿,每个文件最大 16 MiB。不支持旧版 XLS、二进制 XLSB、启用宏的 XLSM、加密工作簿或远程 URL。含宏、ActiveX、嵌入对象或外部工作簿链接的包会被拒绝;普通外部超链接目标会忽略,绝不获取。仅读取支持的普通公式与共享公式,不支持的公式形式会失败。ZIP/XML 校验与资源上限会拒绝损坏、不支持或过大的输入。工作线程与取消功能可减少界面阻塞,但不是浏览器内存的硬隔离。 每个工作簿最多 20 张表、100,000 个单元格、10,000 条物理行记录;实际单元格最大行号 100,000、最大列号 1,024;列区间记录最多 2,048 条,样式 XML 节点最多 10,000 个,共享字符串条目最多 100,000 个,每个文本值最多 32,767 字符,每个公式最多 8,192 字符。ZIP 最多 256 个条目,单条目解压后最多 16 MiB,总计最多 32 MiB,解压倍率最多 200:1;整个包的 XML 深度最多 48、节点最多 600,000 个。有效的全网格声明范围和合并范围可仅作为元数据保留,不会绕过实际单元格上限,也不会按完整区域分配单元格。 整个工作簿的普通公式与展开后的共享公式累计最多 4,194,304 个 UTF-16 代码单元;逻辑标量值与实际数字格式字符串累计最多 16,777,216 个 UTF-16 代码单元,重复引用也累计计数。传给 ExcelJS 的重建核心 XML 包在 ZIP 额外开销前最多为 32 MiB UTF-8 字节。
  • 整本模式严格匹配工作表名称,包括大小写。改名默认表现为旧表删除、新表新增及其单元格事件,除非明确选择左右表对。坐标模式只比较相同地址,移动的值表现为移除、增加或所在坐标的变化;不会推断行列插入、识别移动区域、猜测改名或模糊匹配。 键模式仅用于一对选定工作表。选择一至八个不同的 Excel 列字母,两侧使用相同列位置。忽略表头行及其之前的行;仅物理声明但没有单元格的空行不参与。缺少、空白、空字符串、错误值或公式键,以及重复的带类型复合键,都会阻止比较。文本、数字、布尔与日期表示保持区别,不去空白、不转换大小写、不规范化 Unicode,也不强制转数字。仅行坐标变化会忽略,但变化单元格保留两侧地址。行移动后,声明范围、列、合并范围等工作表元数据仍可能有差异。 两个工作簿的编码后复合键合计最多 6 MiB,即使对应记录完全未变也适用。
  • 单元格比较解码后的带类型值。文本在 XML 与共享字符串解码后比较,布尔值统一为 true/false;同一值的等价编码不作为字节级差异。数字保留 XML 原始文本,不四舍五入,也不使用误差阈值;即使 Excel 显示相同,1、1.0 与 1e0 仍可能不同。缺少单元格、显式空白与空文本不同。公式文本与缓存的带类型结果是独立字段,缓存可能缺失或过期。不重新计算公式,不获取外部链接,看起来像公式的普通文本仍是文本。 数字形式的日期序列值与工作簿的 1900 或 1904 日期系统一起保留,支持的实际数字格式文本另行比较,General 统一表示为没有特殊格式。日期分类使用解析值与支持的数字格式识别,不复现 Excel 的完整显示引擎。显式 ISO 日期文本按存储文本比较;只有工作簿日期系统变化时,不会为其产生依赖历元的单元格变化。不自动换算历元、日历或时区。1900 系统中的序列 60 保持原始存储值,不伪造为有效公历日期。不同日期系统下相同的序列文本不能解释为同一个日历日期。 部分与地区有关的内置格式以 [builtin:27] 这样的 ID 标记表示,已知的日期格式 ID 保留日期类型;工具不会虚构特定地区的显示模式。
  • 结构范围包括工作簿日期系统、工作表是否存在、名称、顺序和可见性、声明的工作表范围、坐标模式中声明的行是否存在、列宽和隐藏区间、合并范围。物理空行记录可能产生坐标模式的行事件;键模式忽略行是否存在的事件。这些是元数据差异,不是重建的编辑历史。比较数字格式,但不比较字体、填充、边框、视觉布局、图表、图片、批注、数据验证规则等未支持特性,因此不是视觉或完整工作簿等价性检查。富文本合并为文本;不会根据合并区域或声明范围生成额外单元格。
  • 每次比较最多 20,000 条事件,序列化事件总量也有上限;每次导出最多 6 MiB,工作线程每次操作有 20 秒期限,实际响应取决于浏览器调度。结果或导出超限会失败,不会悄悄截短。每页 25 条、值预览 600 字符的显示限制不改变导出范围。筛选会同时限定显示和导出的事件;选定某个工作表时,会排除 dateSystem 等工作簿级事件。需要全部差异时请清除所有筛选。 CSV 是 UTF-8 差异报告,表头固定,每个数据字段强制带标签:text: 表示报告文字或地址,null: 表示缺少的元数据,json: 表示修改前后带类型的 JSON 值。需要解码时只去掉最前面的一个标签;json:null 表示缺少单元格,空白单元格则是 JSON 对象。CSV 引号本身不能防止公式。标签让不可信的源文本不直接作为开头的电子表格公式;之后去除标签会重新引入解释风险。JSON 直接保留结构化报告。两种格式都不是替代工作簿、二进制备份或自动补丁。输入与结果不会上传、持久保存或发送到第三方 CDN;站点资源仍正常加载,下载的报告可能包含敏感信息。

常见问题

为什么改名的工作表显示为删除和新增?

整本模式只配对名称完全相同的工作表,不会因为内容相似就猜测它们相同。请明确选择修改前与修改后的工作表,比较该表对,并把名称变化与单元格变化一同列出。

公式变化是否意味着计算结果也变化了?

不一定。公式文本与已存缓存结果分别比较,不执行重新计算。公式改变可能仍带相同缓存,公式未变也可能出现缓存变化或缺失。需要重新计算时,请在可信的电子表格应用中打开副本。

为什么拒绝空白或重复的行键?

它们无法建立明确的一对一匹配。每个键分量必须存在、非空且不是公式,完整带类型元组在两侧各自唯一。文本 001、文本 1 与数字 1 是不同键。请修正源副本或选用合适的复合键。

下载是否只包含当前页?

不是。导出包含当前筛选条件下的全部事件与完整值,但仍受导出大小上限约束。清除筛选可导出整个比较结果。预览可能缩短长值,成功导出不会悄悄缩短它们。

相关工具