Excel 工作簿差异比较
数据互转
正在载入
正在加载工具
工具代码会在打开时按需载入,请稍候。
本工具的全部运算都发生在你的浏览器中,输入内容不会发送到任何服务器。
关于这个工具
比较两个已保存的 XLSX 工作簿,不上传内容,也不修改源文件。默认整本比较按完全相同的工作表名称配对,再按单元格坐标比较;也可明确选择左右各一张表,按一个或多个键列匹配行。报告分别呈现值、类型、公式文本、公式的已存缓存结果、数字格式以及工作簿和工作表元数据。精确比较保留数字的原始存储文本,并区分缺少单元格与显式空白。筛选并分页检查差异后,可导出所有符合筛选条件的类型化 JSON 或带安全标签的 CSV。ExcelJS 4.4.0 与本地 XML 防护在浏览器工作线程运行,不执行公式、宏或外部数据连接。
常见用途
- 在分发新版预算或业务报表前,检查输入值、公式以及可能已过期的公式缓存结果发生了什么变化。
- 以唯一且保留类型的 ID 或复合键对照已重新排序的库存、订单行,区分文本 001 与数字 1,并保留两侧源坐标。
- 在工作簿交接时同时检查单元格变化与工作表增删、顺序、可见性、合并范围、声明范围和列元数据。
使用方法
- 1.选择修改前与修改后的两个 .xlsx 文件,每个不超过 16 MiB,然后读取两侧。查看工作表与日期系统。请使用已保存、未加密的 XLSX 副本;更改 XLS、XLSB 或 XLSM 的后缀并不能转换格式。
- 2.保留整本坐标模式可自动配对名称完全相同的工作表。需要比较改名表时,明确选择左右各一张表。在所选表对中使用坐标模式,或输入最多八个互不重复的键列字母,例如 A,C。键模式要求表头行号为 1 至 1048575,仅处理该行之后实际包含单元格的行。
- 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 是不同键。请修正源副本或选用合适的复合键。
下载是否只包含当前页?
不是。导出包含当前筛选条件下的全部事件与完整值,但仍受导出大小上限约束。清除筛选可导出整个比较结果。预览可能缩短长值,成功导出不会悄悄缩短它们。