目录

OpenXmlNPOIEPPlusSpire.Office组件对EXCEL-ole对象附件的支持

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 - 最底层支持



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 - 需要额外处理



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 - 商业版支持更好


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 - 最便捷


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)
  • 注意内存使用,大附件需要流式处理

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