零依赖的代价与自由:我用 C# 自研了一套 Office 读写库

一套纯 C# 写的 Office 读写库:PDF、Word、Excel 能读能写,DOC/XLS 老格式也能读,0 个第三方 NuGet 依赖 ,MIT 许可。

为什么现在说:主流方案要么贵,要么重,要么挑平台。

对你意味着什么:多一个选择,也多一份"格式标准自己读"的参照。

▲ 深夜写代码的人,大概都动过"自己写一个"的念头

01 那个删掉所有依赖的决定

一套 C# 的 Office 读写库,5 种格式 ,0 个第三方依赖。

这是 Wisdom.Office 现在的样子。PDF、Word、Excel 能读能写,DOC 和 XLS 这类老格式也能读。整个项目不引 EPPlus、不引 NPOI、不引 Aspose,也不靠 COM 互操作。

读写 Office 的老路子,.NET 同学都熟。引第三方库最快,一个包搞定,代价是依赖树越来越长,商业库的授权费按开发者席位收,不便宜。走 COM 互操作,服务器上得先装 Office,Linux 容器里这条直接卡死。还有中间路线:每个库只覆盖一两种格式,攒齐一套还是半打依赖。

这些路我都走过。走完的结论是:把格式标准读懂自己写,比供着一堆包省心。

读写 Office 一定要引组件吗?我试了条最笨的路。

02 Office 文件没你想的那么神秘

自己写的第一步,是承认这些格式并不神秘。

DOCX 和 XLSX 按 OOXML 标准(ISO 29500)来,文件拆开就是 ZIP 加 XML。.NET 自带的 ZipArchive 解包,LINQ to XML 解析,底子是全的。

老一点的 DOC 和 XLS 是另一套规矩:OLE2 复合文档套着 BIFF8 记录流。格式文档同样公开,麻烦在记录类型多,边角情况杂。

PDF 1.7 是对象树加内容流,文字、表格、字体都躺在流里。生成要自己输出对象和字体子集,解析得顺着操作符把文本捞回来。

真正花时间的从来不是主干,是边角:OOXML 的内容类型和关系目标、BIFF8 的样式记录、PDF 的字体嵌入。这些没有捷径,对着规范和真实样本一行行抠。

▲ 解析器不是一天写完的,是对着规范一行行抠出来的

03 零依赖的代价与自由

先说自由。

跨平台是最直接的一条。不靠 COM,Windows、Linux、macOS 一个样。从 .NET Framework 4.6.1 到 .NET 11,两份资产(netstandard2.0 和 net8.0)自动选中,源码里没有一处条件编译。

进程内转换是第二条。DOCX 转 PDF 就是一次方法调用,不用启动 Office,不用等外部进程,Linux 服务端照样跑。

还有三条:无授权费,MIT 许可,商用随便用;五个包按需引,不必全家桶;以及一个统一文档模型------Word 和 PDF 汇进同一套 OfficeDocument,Excel 用 OfficeWorkbook,一套数据导出 PDF、DOCX、XLSX 三种格式。

再说代价。

OLE2 解析器、BIFF8 读取、PDF 生成与提取,全部手写。测试也不能拿自己生成的样本糊弄,得找真实的 .doc 和 .xls 文件回来验。

兼容性同样有边界。这份限制清单,比功能列表值钱:

· .doc、.xls 只支持读取,写不回;

· .xls 只认 BIFF8(Excel 97-2003),公式只保留缓存值;

· PDF 不支持加密文档,保存是依据统一模型重新排版,不保留原始字节和视觉结构;

· PDF 文本提取靠文本操作符,扫描件要额外接 OCR,表格识别是启发式,复杂版式可能得人工校正;

· PDF 字体嵌入只认 TrueType 的 glyf 轮廓,CFF/OTTO 字体嵌不进去;

· Word 和 PDF 不能直接输出成 Excel。

这些限制不是谦虚,是划清能力边界。零依赖换来的自由,是有边界的自由------心里有数,才知道什么时候用它,什么时候换回重型方案。

04 对开发者意味着什么

值不值得用,看场景。先看格式支持情况:

|--------------|----|----------|
| 格式 | 读取 | 写入 |
| PDF 1.7 | 支持 | 支持(重新排版) |
| DOCX | 支持 | 支持 |
| DOC(97-2003) | 支持 | 不支持 |
| XLSX | 支持 | 支持 |
| XLS(BIFF8) | 支持 | 不支持 |

用法不复杂,统一入口五行代码:

using Wisdom.Office; OfficeFile file = OfficeFile.Load("input.xlsx"); Console.WriteLine(file.Format); Console.WriteLine(file.Metadata.Title); file.Save("copy.xlsx");

格式检测不看扩展名,看文件内容签名。

适合的场景:服务端报表导出,一套数据出三种格式;.doc、.xls 老文档抢救;Linux 容器里生成 PDF;模板填充,{{key}} 占位符,支持列表循环。

不适合的场景:复杂排版 1:1 还原;加密文档;扫描件 OCR,得自己接。

项目在 GitHub 上,MIT 许可。五个包版本号一致,nuget.org 尚未发布,可以先源码集成或注册本地源安装。

▲ 真实 .doc / .xls 样本回测,是这套库的日常

零依赖不是技术优越感,是你有权利知道:那些被一个 NuGet 包遮住的东西,底下到底是什么。

写这套库之前没什么宏大叙事,就是不想再供着一堆包过日子。代价是我付的,源码是公开的,自由你可以白拿。

相关推荐
想做小南娘,发现自己是女生喵1 小时前
QT项目实战第一周(嵌入式)
开发语言·qt
学逆向的1 小时前
C 可变量参数
c语言·开发语言·网络安全
andyweike1 小时前
kotlin dsl library工程怎么配置
android·开发语言·kotlin
huaweichenai1 小时前
php搭建mcp服务
开发语言·php·ai编程
估值探索者2 小时前
【Python量化技术指标实战 02】MACD金叉也分强弱?手工算一次 DIF/DEA 就懂了
java·开发语言·python·股票数据·股票数据api接口
讳疾忌医丶2 小时前
编译器眼中的 C++ 循环:从指针别名、IEEE 754 结合律到 SIMD 语义证明
开发语言·c++
重生六道2 小时前
B站视频时长统计:一段JS脚本搞定分P/合集总时长(附倍速计算)
开发语言·javascript·音视频
XiYang-DING2 小时前
P5528.带过期时间的 LRU 缓存
java·开发语言·缓存
小徐不徐说2 小时前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv