# XLSX 读取、结构与查询

[结构、样式与日期解释](structure.html) · [原生结构化查询](query.html) · [原生数据生成](builder.html) · [受控 editor](editor.html)

`fsys.openXml` 0.16.0+ 在 0.15.0 的 A1 区域、结构/样式/日期解释、有界预览和无 Office/ACE 查询基础上，增加普通 `.xlsx` 的固定坐标受控 editor。默认读取的原始值/缓存契约不变。

`fsys.openXml.xlsx`（需要 `fsys.openXml` 0.5.0+）使用共享 ZIP/关系层和系统 MSXML。无需 Excel/WPS 或 .NET，不执行宏、公式、外链或嵌入对象，不修改源文件。读取 XML 工作簿：XLSX、XLSM、XLTX、XLTM、XLAM；不解析传统 XLS、二进制 XLSB 或加密文档。识别依据是包关系、内容类型与命名空间，而不是扩展名。

## 工作表清单

```aardio
import fsys.openXml.xlsx;
var sheets,err = fsys.openXml.xlsx.listSheets("/input.xlsx");
if(!sheets) return null,err;
for i,sheet in sheets {
    print(sheet.index,sheet.name,sheet.kind,sheet.state);
}
return sheets;
```

按 `workbook/sheets` 顺序及 `r:id` 关系定位，支持 Transitional、Strict、不同命名空间前缀及非默认部件路径；不按 ZIP 顺序、文件编号或 sheetId 排序。返回项含 `index,name,sheetId,rid,state,path,partName,kind,contentType,relationshipType`。序号自 1 开始；`path/partName` 都是包内路径。

隐藏/veryHidden 页仍列出。图表页等非 `worksheet` 页列出类型，但读取其单元格会明确报错，不伪装为空工作表。

## 读取一张表

```aardio
import fsys.openXml.xlsx;
var data,err = fsys.openXml.xlsx.readSheet("/input.xlsx",1,{
    maxRows = 200;       // 选取原始行数，含标题行和区域内空行
    maxColumns = 30;
});
if(!data) return null,err;

for i,cell in data.cells {
    print(cell.ref,cell.value,cell.formula,cell.hasCachedValue);
}
return data;
```

第二个参数可省略，也可用精确工作表名称、包内部件名或 `listSheets` 返回项；描述符必须对应本工作簿实际列出的页，不能借此任意读取部件。

结果包含：

- `path,mainPart,date1904,sheet`：文件路径、主部件、保存的日期基准、页描述。
- `startRow,startColumn,rowCount,columnCount`：所返回区域的绝对起点与尺寸。
- `rows`：相对于起点的二维值数组，不自动提取标题、不 trim、不跳过区域内的空行。
- `cells`：区域内实际存在的单元格描述列表，含没有值的自闭合单元格。
- `warnings,truncated`：功能边界提示与显式区域选择/限额截取标记。
- `dimension`：文件保存的原始 dimension 声明，仅供参考；范围根据实际单元格计算。

**缺格/缺值为 `null`，与 `0`、`false`、存在的空字符串不同。** 每行的普通 `length` 字段保存完整列宽，可跨线程传递；`JSON.stringify(row)` 会保留前导、中间和尾部空格。aardio 的 `#row` 只计算稠密部分，不应用它或泛型 `for in row` 遍历稀疏单元格；请用 `for(c=1,data.columnCount)` 或 `table.len(row)`。整个 `rows` 数组的行序号是连续的。

空工作表成功返回空数组、起点和尺寸均为 0。空单元格、空行不等于 XML 损坏或缺 `sheetData`；后者报错。

### 单元格值与公式

单元格描述保留 `ref,row,column,type,valueType,value,raw,hasValue`，按存在情况附带 `styleIndex,sharedStringIndex,error,formula,formulaType,formulaRef,sharedIndex`；总有 `hasFormula,hasCachedValue`。

- 数字按有限数值读取，`raw` 保留 XML `<v>` 的解码文本。aardio 数值为双精度，需要保留大整数原文时使用 `raw`。
- 共享字符串与内联富文本按 run 拼接，保留有效空白；不把 `rPh` 注音混入正文。XML 实体只解码一次；字符串的 `_xHHHH_` 按 ST_Xstring 单次解码，支持受保护下划线和代理对。
- `t="b"` 返回布尔值；`t="str"` 保持字符串，`00123` 不变成数字；错误类型保留错误码。
- `t="d"` 保留保存的 ISO 日期字符串；它不是根据数字样式推算出来的日期。
- **公式与缓存分开。** `formula` 为保存的公式正文，不加 `=`；共享公式从属格可以只有索引而无公式正文。不推算共享/数组公式，不访问外部链接。`value` 仅取保存的缓存，缓存可能过期；没有缓存或数字缓存 `<v/>` 时为 `null`，不是 0。`hasCachedValue` 表示存在可读缓存，不表示它最新。
- 默认只保留 `date1904` 与 `styleIndex`，不加载样式。可显式 `includeStyles=true` 读取保存的基础样式，`parseDates=true` 附加日期/时间/时长 `interpretation`，原始值不变。它不是最终显示文本；精确显示仍走 Office/WPS COM，见[结构与日期](structure.html)。

不展开合并单元格、不根据筛选/隐藏状态删行、不计算表格公式，不处理图表、透视表、数据模型或完整 MC 视图。按 XML 中已保存的 worksheet 单元格读取；`warnings` 不是所有未支持内容的完整清单。

## 选区、内存与失败

所有入口接受通用包/XML 安全限额，见上级指南。

| 选项 | 默认 | 说明 |
|---|---|---|
| `range` | 未指定 | 本页 A1 有限矩形，与起点选项互斥；保留显式空边界 |
| `includeStructure` | false | 整页合并、行列、表对象与整簿名称定义 |
| `includeStyles/parseDates` | false | 附加保存样式/日期解释，不改变原值 |
| `startRow` / `row` | 实际最小行 | 自 1 起始的绝对起点；`startRow` 优先 |
| `startColumn` / `column` | 实际最小列 | 自 1 起始的绝对起点；`startColumn` 优先 |
| `maxRows,maxColumns` | 不限 | 非负整数，0 不取；限制返回的矩形区域 |
| `includeRows` | true | false 仅保留单元格清单，不展开矩形 |
| `includeCells` | true | false 不返回单元格描述列表 |
| `maxMatrixCells` | 1000000 | 一次调用所有返回矩形的累计格数上限，最高 10000000；超限报错 |
| `maxSheets` | 不限 | `readWorkbook/extractText` 返回前 N 页；0 不取 |
| `keepErrors` | false | 整簿默认任一页失败就失败；true 保留错误项并继续 |
| `maxTextBytes` | 16777216 | `extractText` 最终文本的 UTF-8 字节上限，含分隔符，最高 134217728；必须为正整数，超限报错 |

行号最大 1048576、列号最大 16384（XFD）。`maxRows/maxColumns` 不超过相应界限。坐标重复、越界或未递增、缺失必要关系、非法类型/索引等会报告错误。

矩形限额避免两格相距极远时盲目构造巨大矩阵；可限制区域或使用 `includeRows=false` 读取稀疏 `cells`。文本限额也会检查共享字符串重复引用后的展开量，而不只依赖 ZIP 字节数。

这是 DOM 读取器，不是流式 Excel 引擎。选区仍需要解析整张被选工作表并处理单元格，共享字符串在实际引用时加载；`maxRows` 不是解析前内存上限。一个 `readWorkbook` 调用只打开一次包，跨工作表复用已解析共享字符串，通用读取字节预算按整个调用累计。

读取失败返回 `null,err`。整簿在已完成一些页后失败可返回第三值 `partial`；`keepErrors=true` 时失败页包含 `sheet,error`，顶层增加 `errorCount`。`complete=true` 表示没有错误且没有截取；区域选择或 `maxSheets` 截取用 `truncated=true` 表示。清单或正文读取成功不代表未读取媒体/样式等部件已校验 CRC。

## 整簿与文本

`readWorkbook(path,options)`（别名 `read`）返回 `path,mainPart,date1904,sheetCount,sheets,warnings,truncated,errorCount,complete`。`sheetCount` 始终是源工作簿页数，`sheets` 为读取结果，各项同 `readSheet`。

```aardio
import fsys.openXml.xlsx;
var data,err = fsys.openXml.xlsx.extractText("/input.xlsx",{
    maxSheets=3;maxRows=200;maxColumns=30;maxTextBytes=1048576;
});
if(!data) return null,err;
print(data.text);
return data;
```

`extractText` 在整簿及各成功页上增加 `text`。TAB 分列、CRLF 分行、两个 CRLF 分页，不省略稀疏空格；它强制生成矩阵并受矩形/文本预算限制。单元格内原有 TAB/换行不做 CSV 转义，因此这只是可读摘要，不是可逆 CSV 导出。

## 条目与媒体

`listEntries(path,pattern,options)` 保留真实 ZIP 目录项；`pattern` 为可选 aardio 模式。`listMedia(path,options)` 列出 `xl/media/` 及实际主部件同级 `media/` 下的文件（含子目录和未引用项），不构建全部资源关系图。

```aardio
import fsys.openXml.xlsx;
var result,err,partial = fsys.openXml.xlsx.extractMedia("/input.xlsx","/media",{
    overwrite=false;
});
if(!result) return null,err,partial;
return result;
```

导出复用公共媒体辅助：默认不覆盖；末级文件名平铺，同名预检；CRC/长度/限额检查后逐文件提交。返回 `outputDir,files,skipped`，失败为 `null,err,partial`，不是整批事务。可用 `maxMedia` 限制成功导出数，跳过不计数；0 不导出。

## Excel 技能兼容层

`autos.skills.excel` 的七个旧入口 `listXlsxEntries/listXlsxSheets/readXlsxSheet/extractTextFromXlsx/listXlsxMedia/extractXlsxMedia/readWorkbookByZip` 以及 `readSheet` 的 ZIP 分支统一转发到本库。保留旧主要字段、`method="zip"`、标题字段整理及行号等选项。

- 技能的内容限额 `maxRows/maxColumns/maxSheets/maxMedia` 支持数字字符串，0 兼容为未指定；这不同于原生入口的 0 不取。安全限额仍受默认上限约束。
- `readSheet` 默认首行作标题、trim 字符串、跳过全空行；`asMatrix=true` 返回原始矩阵，现在也遵守行列限额，附加 `rows.info` 警告/截取信息。
- 修复纯数据 `rowsToTable` 的 0/false 丢失、稀疏行宽推断和整簿 `_row` 起始行偏移；不改 Office/WPS COM 实现。
- 坏包/坏页不再静默丢弃或伪装空成功；需要收集坏页请显式 `keepErrors=true`。
- 旧媒体入口默认覆盖；显式 `overwrite=false` 或 `0` 仍不覆盖。成功返回文件数组，第三值为原生导出明细；旧 `formattedSize/path/source` 等字段保留。子目录媒体现在也统一列出并平铺导出。
- COM、SQL 及默认 auto 的优先级不变；仅调用 ZIP 入口时才加载本读取器。
- 技能0.4.0增加 `inspectXlsx/queryXlsx/findXlsxCells` 薄入口，直接采用本库0.15.0的严格选项/0限额语义，不套用旧兼容转换，不启动 Office/数据库。
- 技能0.6.0增加 `openXlsxEditor` 薄入口；它只打开普通 `.xlsx` 的受控固定坐标编辑会话，不改变旧 `readSheet/readWorkbook`、COM、SQL 或 auto 选路。
