Excel 与数据

客户给的 Excel 不要直接重存:先检查外部链接

keep_vba=True 是保留策略,不是“检测到宏”的证据。下面只盘点 ZIP 包是否存在 vbaProject.bin 与外部链接部件;部件存在不代表内容安全、宏有效或外部目标可访问。不会执行宏或访问链接。

阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。 这篇先解决哪一个问题 keep_vba=True 是保留策略,不是“检测到宏”的证据。下面只盘点 ZIP 包是否存在 vbaProject.bin 与外部链接部件;部件存在不代表内容安全、宏有效或外部目标可访问。不会执行宏或访问链接。 自包含的合成示例 依赖见导入列表。代码在内存中构造输入;运行记录单独提供,不代表对所有真实文件的保证。 from io import BytesIO from zipfile import ZipFile from openpyxl import Workbook def inventory(raw): with ZipFile(BytesIO(raw)) as z: names = set(z.namelist()) return {"has_vba_part": "xl/vbaProject.bin" in names, "external_link_parts": sorted(n for n in names if n.startswith("xl/externalLinks/externalLink") and n.endswith(".xml"))} out = BytesIO() Workbook().save(out) assert inventory(out.getvalue()) == {"has_vba_part": False, "external_link_parts": []} synthetic = BytesIO() with ZipFile(synthetic, "w") as z: z.writestr("xl/vbaProject.bin", b"not executable VBA; fixture only") z.writestr("xl/externalLinks/externalLink1.xml", b"<fixture/>") result = inventory(synthetic.getvalue()) assert result["has_vba_part"] assert result["external_link_parts"] == ["xl/externalLinks/externalLink1.xml"] 客户发来的 Excel 文件在本地打开正常,但经过 Python 脚本处理或上传系统后,公式变成 #REF! 、下拉菜单消失,甚至直接报错无法打开。这通常不是文件损坏,而是自动化工具在“重存”时未能正确维持外部链接缓存或 VBA 宏的完整性。openpyxl 作为轻量级库,其设计重心在于单元格数据读写,而非完整复刻 Excel 运行时环境。若不加干预地加载并保存,输出的文件可能是一份残缺副本。 为什么默认加载会丢失关键信息 openpyxl 官方文档明确指出, load_workbook 对非单元格数据的处理有严格边界。虽然 keep_links 参数默认为 True ,但这仅表示保留 XML 中的链接定义,并不保证链接指向的外部数据缓存(Cached Values)在重存后依然有效;一旦脱离原始网络环境或源文件路径,Excel 刷新时仍可能报错。更关键的是 keep_vba 参数默认为 False ,这意味着如果原文件包含自动化宏,默认加载后再保存,VBA 项目将被永久移除。此外,图表、形状(Shapes)等对象在读取时也可能被忽略。这不是 bug,而是库的功能边界。在处理生产级文件时,必须显式声明保留策略,而不是假设工具会自动“智能”保留所有特性。 合成示例与测试文件准备 为了安全演示这一机制,我们需要构造一个不依赖真实客户数据的合成场景。 请务必按以下步骤准备测试文件 input_check.xlsx :新建一个 Excel 工作簿,在 VBA 编辑器(Alt+F11)中插入一个空白模块,并在单元格 A1 中输入公式 ='[ExternalBook.xlsx]Sheet1'!$A$1 (无需实际创建外部文件,仅需保留此引用结构),最后另存为启用宏的格式 input_check.xlsm 。 错误/边界输入处理 :如果对同一个启用了宏的文件使用默认的 load_workbook('input_check.xlsm') 加载,然后保存为 .xlsx 格式,VBA 代码将被静默丢弃。更危险的是,如果加载时未指定 keep_vba=True 却强行保存为 .xlsm ,Excel 可能会因文件头与实际内容不符而拒绝打开。另一个边界情况是只读模式( read_only=True ),该模式下 keep_links 和 keep_vba 参数无效,任何试图保留特性的操作都会失败。 外部链接与宏保留的校验代码 以下 Python 示例展示了如何在内存中构造检查逻辑。请注意,此代码仅为演示参数作用的教学示例,并非完整的文件修复工具,且未在实际生产环境中执行过。运行前请确保已按上文准备好 input_check.xlsm 文件。 验收标准与人工审查边界 自动化处理永远无法覆盖 Excel 的所有边缘情况。下表基于 openpyxl 的已知限制整理,用于区分哪些任务可以交给脚本,哪些必须拦截。 此表明确区分了“代码演示”与“端到端效果”。脚本能验证参数是否生效,但不能保证输出文件在业务层面可用。例如,即使 keep_links=True 成功保留了链接定义,如果目标服务器已下线,用户在 Excel 中刷新时依然会报错。这类问题超出了文档处理库的职责范围,必须在验收流程中预留人工复核环节。 参考与下一步 openpyxl Tutorial: Loading from a file openpyxl Tutorial: Saving to a file 下一步行动:在你的测试环境中准备三个样本文件(纯数据 .xlsx、带宏 .xlsm、含外部链接 .xlsx),分别用默认参数和保留参数加载并保存,对照上表记录实际结果。只有当你清楚知道每个参数在你的文件集上产生什么后果时,才能安全地将自动化脚本部署到生产流程中。 具体异常的处理决定 观察 应做什么 不应推断 存在 VBA 部件 提示含需另审的内容 不执行宏 外部链接部件 记录包内位置 不访问目标 保留参数开启 视为加载策略 不当作检测到宏的证据 将这份检查清单用于文档翻译 先决定哪些是文字、哪些是公式和业务编码,再做表格翻译。译后检查不仅包括中文是否变成目标语言,也包括公式、标识符和引用关系有没有被改变。 OmniDoc(产品入口) 提供多格式文档翻译入口,官网介绍了 OCR、术语表与双语对照功能。对希望直接从文件开始处理的团队,这是一条值得用实际样本评估的路径。请使用有权上传的脱敏文件,并用本篇的检查项复核结果;这里不声称 OmniDoc 使用了本文的开源库或内部算法,也不以示例代替产品性能测试。 - 1 -
更新于 2026-10-09