epplus是目前唯一能稳定提取xlsx批注文本、作者及位置的主流库;需用v6.2+或v5.8.7,启用licensecontext,从worksheet.drawings中遍历excelcomment对象,通过address匹配单元格,text读纯文本,author取作者,top/left为像素坐标。

用 EPPlus 读取 XLSX 批注最稳
直接说结论:别碰 Microsoft.Office.Interop.Excel,它依赖 Office 安装、线程不安全、服务器跑不起来;NPOI 对 XLSX 批注支持极弱(v2.5+ 虽加了 Comment 类但实际读不到内容);EPPlus 是目前唯一能稳定提取批注文本、作者、位置的主流库。
实操建议:
- 用
EPPlusv6.2+(.NET 5+)或 v5.8.7(.NET Framework 4.6.1+),老版本有批注解析空指针问题 - 加载时必须启用富文本支持:
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;(开源版)或填商业授权,否则部分批注字段为 null - 批注不是“单元格属性”,而是独立对象,需通过
worksheet.Drawings查找,不是cell.Comment
worksheet.Drawings 里找批注对象
很多人卡在这步:以为 cell.Comment.Text 就是批注内容,其实 XLSX 的批注是 Drawing 对象(ExcelComment),藏在 Drawings 集合里,和单元格是松耦合关系。
常见错误现象:cell.Comment 始终为 null,或读出来是空字符串——那是因为你没从 Drawings 里匹配。
实操建议:
- 遍历
worksheet.Drawings,过滤出ExcelComment类型:var comments = worksheet.Drawings.OfType<excelcomment>();</excelcomment> - 每个
ExcelComment有Address属性(如"A1"),用它反查对应单元格:worksheet.Cells[comment.Address] -
comment.Text是纯文本,comment.RichText可读格式化内容(含字体/颜色),但注意:部分 Excel 导出的 XLSX 会把换行存成\r\n,需手动替换
批注作者、时间、位置怎么对应上
XLSX 批注元数据分散在不同地方:作者名在 comment.Author,但可能为空(尤其从 WPS 或网页导出);创建时间不在 ExcelComment 上,得查 comment.Workbook.PackagingProperties.Created(整个文件时间,非单条批注);位置靠 comment.Top/comment.Left,但这是像素偏移,对齐逻辑得自己算。
使用场景:做审计日志或协作痕迹分析时,不能只信 Author 字段。
实操建议:
- 优先用
comment.Author,为空时 fallback 到comment.Workbook.Properties.Creator(文件创建者) - 单条批注时间不可靠,
EPPlus不暴露修改时间戳,除非你解析底层 XML(worksheet.WorksheetXml里的<comment></comment>节点带date属性,但需手动 XPath 提取) - 位置坐标
Top/Left是相对于工作表左上角的像素值,和行高列宽无关;想转成“第几行第几列”,只能靠comment.Address字符串解析
性能与兼容性踩坑提醒
大文件(>10MB,>10w 行)下,EPPlus 加载时默认会把所有 Drawing 全解包,批注多的话内存暴涨。另外,Mac 版 Excel 生成的 XLSX 常把批注作者写成邮箱格式("user@domain.com"),而 Windows 版写成昵称("张三"),业务逻辑得兼容。
实操建议:
- 用
new ExcelPackage(stream, false)禁用自动解压 Drawing,之后按需调用worksheet.Drawings.Load() - 读批注前先
if (worksheet.Drawings.Count == 0) return;快速跳过无批注表 - 作者字段统一做 Trim() + 正则清洗:
Regex.Replace(author, @"<.>", "")</.>去掉邮箱尖括号
批注解析真正的复杂点不在代码行数,而在“谁写的”“什么时候写的”“到底附在哪一格”这三件事,Excel 标准本身就没强制约束,各家实现松散——所以别指望一个 .Text 属性就拿到全部信息。










