OpenXml、NPOI、EPPlus、Spire.Office组件对EXCEL ole对象附件的支持

OpenXml、NPOI、EPPlus、Spire.Office 对EXCEL插入附件的读取支持情况(比如插入ZIP文件)

这些主流Excel操作库对插入附件(如ZIP文件)的支持情况如下:

📊 支持情况对比

库名称 版本 附件读取支持 实现方式 备注
OpenXml 2.20+ ✅ 完全支持 直接操作OLE对象 最底层,最灵活
NPOI 2.7+ ✅ 支持 通过OLE对象访问 需要额外处理
EPPlus 5.8+ ⚠️ 有限支持 通过OLE对象 商业版支持更好
Spire.Office 13.8+ ✅ 支持 内置方法 商业库,功能完整

🔧 各库具体实现

1. OpenXml SDK - 最底层支持

cs 复制代码
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

public void ExtractAttachments(string filePath, string outputDir)
{
    using (var spreadsheet = SpreadsheetDocument.Open(filePath, false))
    {
        var workbookPart = spreadsheet.WorkbookPart;
        
        // 获取所有OLE对象
        foreach (var oleObject in workbookPart.OleObjectsPart?.OleObjects.Elements<OleObject>())
        {
            var objectId = oleObject.Id.Value;
            var embeddedObjectPart = (EmbeddedObjectPart)workbookPart.GetPartById(objectId);
            
            // 保存附件
            using (var stream = embeddedObjectPart.GetStream())
            {
                var fileName = $"attachment_{objectId}.bin";
                File.WriteAllBytes(Path.Combine(outputDir, fileName), ReadStream(stream));
            }
        }
    }
}

private byte[] ReadStream(Stream stream)
{
    using (var memoryStream = new MemoryStream())
    {
        stream.CopyTo(memoryStream);
        return memoryStream.ToArray();
    }
}

2. NPOI - 需要额外处理

cs 复制代码
using NPOI.XSSF.UserModel;
using NPOI.SS.UserModel;

public void ExtractAttachmentsNPOI(string filePath, string outputDir)
{
    using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        var workbook = new XSSFWorkbook(fs);
        var xssfWorkbook = (XSSFWorkbook)workbook;
        
        // 获取所有嵌入对象
        var package = xssfWorkbook.GetPackage();
        foreach (var partName in package.GetPartsByName("/xl/embeddings/.*"))
        {
            var part = package.GetPart(partName);
            using (var stream = part.GetInputStream())
            {
                var fileName = Path.GetFileName(partName.Name);
                File.WriteAllBytes(Path.Combine(outputDir, fileName), ReadStream(stream));
            }
        }
    }
}

3. EPPlus - 商业版支持更好

cs 复制代码
using OfficeOpenXml;

public void ExtractAttachmentsEPPlus(string filePath, string outputDir)
{
    ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
    
    using (var package = new ExcelPackage(new FileInfo(filePath)))
    {
        // EPPlus 5.8+ 商业版支持
        var workbook = package.Workbook;
        
        // 通过自定义方式访问OLE对象
        foreach (var worksheet in workbook.Worksheets)
        {
            var drawings = worksheet.Drawings;
            foreach (var drawing in drawings)
            {
                if (drawing is ExcelOleObjectDrawing oleObject)
                {
                    // 商业版功能
                    var content = oleObject.Content;
                    if (content != null)
                    {
                        File.WriteAllBytes(Path.Combine(outputDir, $"ole_{oleObject.Name}.bin"), content);
                    }
                }
            }
        }
    }
}

4. Spire.Office - 最便捷

cs 复制代码
using Spire.Xls;

public void ExtractAttachmentsSpire(string filePath, string outputDir)
{
    Workbook workbook = new Workbook();
    workbook.LoadFromFile(filePath);
    
    // 直接获取所有OLE对象
    foreach (Worksheet sheet in workbook.Worksheets)
    {
        foreach (Spire.Xls.OleObject oleObject in sheet.OleObjects)
        {
            // 获取附件数据
            byte[] data = oleObject.Data;
            string extension = GetFileExtension(oleObject.ObjectType);
            
            File.WriteAllBytes(Path.Combine(outputDir, 
                $"attachment_{sheet.Name}_{oleObject.Location.Row}_{oleObject.Location.Column}{extension}"), 
                data);
        }
    }
}

private string GetFileExtension(OleObjectType objectType)
{
    switch (objectType)
    {
        case OleObjectType.Package: return ".zip";
        case OleObjectType.AcrobatDocument: return ".pdf";
        case OleObjectType.WordDocument: return ".doc";
        default: return ".bin";
    }
}

📋 功能对比详情

OpenXml SDK

  • 优点: 最底层控制,支持所有附件类型

  • 缺点: 代码复杂,需要深入了解OOXML结构

  • 适用: 需要完全控制的高级场景

NPOI

  • 优点: 开源免费,支持基本附件操作

  • 缺点: API不够直观,需要手动处理Package

  • 适用: Java/.NET跨平台项目

EPPlus

  • 优点: API友好,性能优秀

  • 缺点: 免费版附件功能有限,商业版较贵

  • 适用: 简单Excel操作,商业项目

Spire.Office

  • 优点: 功能完整,API简单易用

  • 缺点: 商业收费,免费版有限制

  • 适用: 企业级应用,需要快速开发

🎯 推荐选择

  1. 完全免费 → NPOI

  2. 企业项目 → Spire.Office

  3. 底层控制 → OpenXml SDK

  4. 已有EPPlus → 升级到商业版

⚠️ 注意事项

  • 附件可能存储在/xl/embeddings/或/xl/oleObjects/路径

  • ZIP文件通常作为OLE Package对象插入

  • 需要处理不同的内容类型(MIME types)

  • 注意内存使用,大附件需要流式处理

根据你的具体需求和技术栈选择合适的库。

相关推荐
Highcharts.js18 分钟前
React 中原生支持使用 JSX 组件配置自定义表格 Highcharts Grid
前端·javascript·react.js·前端框架·jsx·highcharts·自定义表格
薛定谔的猫-菜鸟程序员42 分钟前
Electron开发超详细教程(从入门到放弃)
前端·javascript·electron
最强小杰1 小时前
DeepSeek V4 Flash + Codex CLI 接入教程:原生 Responses API 适配,从配置到跑通收藏这篇就够了(2026)
java·前端·python·ai
静水leo2 小时前
使用 Whistle 拦截接口并模拟后端响应
前端
掘金者阿豪2 小时前
SQL Server数据迁移完成后,凌晨的数据库告警该怎么查?
前端·后端
JudithHuang2 小时前
React 嵌套路由与布局
前端·react.js·arcgis·react·react router
htzyl2062 小时前
前端阶梯——第四十三章、实战二:待办清单To-Do
前端·javascript·html
摹客3 小时前
【3D设计】界面设计中的3D元素:应用场景+5款工具横评(含Three.js)
前端
Hilaku3 小时前
CORS 到底在保护谁?90% 的前端理解错了跨域的本质
前端·javascript·程序员