HotXLS 可以打开一个 XLSX 工作簿而完全不解析任何工作表单元格。TXLSXWorkbook.MetadataOnly 读取工作簿属性、已定义名称、工作表名与可见性状态、样式、主题、连接和外部链接,然后在到达单元格 XML 之前停下。对一个需要知道某个工作簿目录里都装了什么的扫描器来说,这就是几分钟与几秒之间的差别
三个相关开关补全了这幅图:SelectedSheets 仅为命名的子集解析单元格,LoadSheet 之后从原始压缩包里按需实体化某个被跳过的工作表,PreserveRawParts 则在保存时把未修改分部的压缩字节原样复制过去。三者合起来,把"打开工作簿"从一次要么全要么无的操作,变成一件你可以限定范围的事
不解析一个单元格能了解什么
比大多数发现任务需要的还多。在 Open 之前把 MetadataOnly 设上,工作簿返回时带着工作表名与可见性状态、已定义名称、文档属性、样式与主题、外部链接和连接。工作表作为对象存在,但单元格数为零
这恰恰是一份目录、一次审计或一次路由决策所依赖的信息。哪些工作簿定义了一个叫 TaxRate 的名称?哪些有隐藏工作表?哪些链接到了一台已经下线的服务器?为了回答这些问题而把每个文件完整加载,正是夜班任务变成通宵任务的方式
var
Workbook: TXLSXWorkbook;
I: Integer;
begin
Workbook := TXLSXWorkbook.Create(nil);
try
Workbook.MetadataOnly := True; // set before Open
Workbook.Open(FileName);
for I := 1 to Workbook.Sheets.Count do // Sheets[] is 1-based
if not Workbook.Sheets[I].Visible then
Report.Add(FileName + ': hidden sheet ' +
Workbook.Sheets[I].Name);
finally
Workbook.Free;
end;
end;
从四十张表里加载两张
SelectedSheets 是一个装工作表名的 TStringList。当它非空时,Open 只为列在其中的工作表解析单元格 XML;其他每张表保留正确的工作表名和可见性状态,但不持有任何单元格。空列表意味着旧行为,也就是全部加载
它与 MetadataOnly 的相互作用值得直说,因为搞反了会得到一个让人摸不着头脑的空工作簿:MetadataOnly = True 覆盖选择并跳过所有工作表。二选一,别同用。发现用仅元数据;定向工作用选择
Workbook.SelectedSheets.Add('Summary');
Workbook.SelectedSheets.Add('Q3 Detail');
Workbook.Open('consolidated-2026.xlsx');
// Later, when the user opens a tab you skipped.
// LoadSheet takes the 0-based position and needs the source file,
// so it does not work on a workbook opened from a stream
if Workbook.LoadSheet(ZeroBasedPosition) then
Grid.Refresh;
LoadSheet(Index) 按需从原始压缩包实体化一张被跳过的工作表,正是这一点让这种模式能在交互式应用里用起来,而不仅仅用在批量里。打开时只加载用户正在看的那张,其余的等用户点击时再加载。正是为此,压缩包保持打开,所以只要用户可能还要问另一张表,就让工作簿活着
为什么一次往返会改动你从没碰过的分部
因为一次天真的保存会重新生成一切。解压主题、构建对象模型、把它序列化回去、再压缩——字节就不一样了,哪怕主题的内容根本没变。对于 VBA 工程和透视缓存(pivot cache)来说这比浪费更糟,因为这些分部携带着对象模型无法完整表示的结构
PreserveRawParts 通过在 SaveAs 时把未修改分部的压缩表示直接从源压缩包复制走,从而回答了这个问题。主题、VBA 工程、透视表和透视缓存在没被修改时以字节形式原样过户。没有解压,没有再压缩,没有在序列化往返中丢东西的风险
代价是一条你本就有的约束:源压缩包在保存时必须仍然可得。如果你的工作流把文件读进内存、关闭它、一小时后再保存,原始复制路径就没有可复制的东西。在工作簿整个生命周期内保持源可达,这正是 LoadSheet 同样施加的要求
一个有意重新打开的发现流水线
生产中行之有效的模式有两趟、没有花活。第一趟仅打开元数据并做决策。第二趟用工作表选择重新打开要紧的文件并干活。重新打开感觉浪费,直到你数清第一趟避开的东西:第二次打开是唯一一次解析单元格的打开,而且它只解析第一趟选中的工作表
// Pass 1: discovery
Workbook.MetadataOnly := True;
Workbook.Open(FileName);
Wanted := SheetsMatching(Workbook, 'Invoice');
Workbook.Free;
// Pass 2: targeted load
Workbook := TXLSXWorkbook.Create(nil);
Workbook.SelectedSheets.AddStrings(Wanted);
Workbook.Open(FileName);
不要试图在 Open 之后清掉标志来就地提升一个仅元数据的工作簿。标志是在打开期间读取的;之后清掉它,对一个单元格 XML 从未被访问过的工作簿不会有任何改变
这与其他大文件杠杆的关系
选择性加载削减的是你解析的内容。它不削减一张表一旦加载后的开销,也帮不上你确实需要每张表每个单元格的情况。对那种情况,相关的工作在存储那一侧,描述在 行块单元格存储与区间样式叠加的笔记里,以及在解析那一侧的 并行 XLSX 解析与内存分配器里。当任务是纯扫描、完全没有编辑时,流式直接读取器完全跳过对象模型,会胜过任何构建对象模型的加载策略
HotXLS 用原生 Delphi 和 C++Builder 代码打开 XLS 和 XLSX 文件,不依赖 Excel,所以一台服务端发现任务除了你自己的可执行文件之外什么也不装就能运行——支持的格式与授权见 HotXLS 电子表格组件页