[异常排查] C# NPOI导入Excel报错: Wrong Local header signature

#代码星辉·七月创作之星挑战赛#

运行环境

  1. 后端框架: ASP.NET Core 5.0
  2. NPOI:2.5.3

问题描述

使用前端导入 Excel.xlsx 类型文件时,后端获取到文件流 Stream 后,通过NPOI转换 StreamXSSFWorkbook 类型时抛出异常 ICSharpCode.SharpZipLib.Zip.ZipException:“Wrong Local header signature: 0x65231462”

根本原因

Excel 被系统加密,导致代码无法正常读取

解决方案

将对应 Excel 解密即可

问题追踪

  1. 通过 VS 进行断点调试,调用堆栈如下
    ICSharpCode.SharpZipLib.Zip.ZipInputStream.GetNextEntry()
    NPOI.OpenXml4Net.Util.ZipInputStreamZipEntrySource.ZipInputStreamZipEntrySource(ICSharpCode.SharpZipLib.Zip.ZipInputStream)
    NPOI.OpenXml4Net.OPC.ZipPackage.ZipPackage(System.IO.Stream, NPOI.OpenXml4Net.OPC.PackageAccess)
    NPOI.OpenXml4Net.OPC.OPCPackage.Open(System.IO.Stream)
    NPOI.Util.PackageHelper.Open(System.IO.Stream)
    NPOI.XSSF.UserModel.XSSFWorkbook.XSSFWorkbook(System.IO.Stream)
    
  2. 抛出异常的地方函数为 ZipInputStream.GetNextEntry(),其具体代码大致如下
    public ZipEntry GetNextEntry()
    {
        if (crc == null)
        {
            throw new InvalidOperationException("Closed.");
        }
        if (entry != null)
        {
            CloseEntry();
        }
        int num = inputBuffer.ReadLeInt();
        //略
        if (num != 67324752)
        {
            throw new ZipException("Wrong Local header signature: 0x" + $"{num:X}");
        }
        //略
        return entry;
    }
    
    ReadLeInt() 方法通过从 inputBuffer 中读取 int 类型,获得数字 num,即为异常中提示的 Local header signature,当 local header signature 不为十进制数字67324752(即十六进制数字 0x4034B50 时),系统判定其有异常并抛出。
  3. 什么是 Local header signature ?
    局部文件头 (Local File Header) 是 Zip 文件结构中用于描述单个文件元数据的部分,位于文件开头,包含文件的通用标志、压缩方式、时间戳等信息,其具体结构可以查看规范文档
    而局部文件头签名 (Local file header signature) 是局部文件头中一个4字节的字段,用于标识局部文件头的开始。对于 Zip 文件格式,这个签名固定为十六进制值 0x04034b50,因此当该字段不符合固定值时,自然被认定为文件异常或损坏,从而抛出异常。
  4. 为什么对于 Excel 的解析,要使用Zip格式进行处理呢?
    Excel 文件本身不是 Zip 压缩格式,但其包含了压缩技术,从 Excel 2007 开始,Microsoft 采用了基于XML的开放文件格式(如xlsxxlsm),这些文件本质上是由多个XML 文件组成的压缩包,通过特定结构存储数据

最佳实践

在应用开发过程中,对于加密文档,对此类异常进行单独 catch,提示用户文件已加密,而非简单抛出异常,从而优化用户体验

Code

 using ICSharpCode.SharpZipLib.Zip;
 using NPOI.SS.UserModel;
 using NPOI.XSSF.UserModel;

 namespace MonitCode
 {
     internal class Program
     {
         static void Main(string[] args)
         {
             string filePath = @"D:\test.xlsx";

             try
             {
                 using Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                 if (null == fileStream)
                 {
                     throw new NullReferenceException("Extract fileStream failed");
                 }

                 IWorkbook workBook = new XSSFWorkbook(fileStream);
                 //do something
             }
             catch (ZipException)
             {
                 Console.WriteLine("Excel文件已加密, 请先解密");
             }
             catch (Exception ex)
             {
                 Console.WriteLine(ex);
             }
         }
     }
 }

结语

说到这里,既然 Excel 包含 Zip 压缩技术,那么,能否使用处理压缩包的方式,对于 Excel 进行一些有意思的操作呢,欢迎大家评论区留言讨论

相关链接

Zip 文件格式规范文档:https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.2.0.txt

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值