ASP.NET Core 5 MVC如何直接输出服务端Zip压缩包内的文件流给用户
报错根因
你遇到的Stream does not support reading异常本质是流生命周期提前结束导致的:
你代码中的FileStream、ZipArchive都包裹在using代码块中,当Action执行到return语句时,using块会自动销毁这两个对象,ZipArchiveEntry.Open()返回的流依赖这两个对象存在,自然也会被提前释放。等ASP.NET Core底层要读取流数据向客户端输出时,流已经处于不可用状态,就会抛出对应异常。
实现方案
我们只需要把压缩包相关的资源生命周期和ASP.NET Core的响应生命周期绑定,让资源在响应完全输出到客户端之后再释放即可,修改后的代码如下:
string zipFile = @"D:\all_installs.zip"; // 以只读权限打开压缩包文件流,暂时不手动释放 FileStream fs = new FileStream(zipFile, FileMode.Open, FileAccess.Read); // 明确指定只读模式打开ZipArchive,避免权限问题 ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read); // 查找目标条目,记得加判空逻辑 ZipArchiveEntry entry = zip.Entries.FirstOrDefault(x => x.FullName == "downloadable file.iso"); if (entry == null) { // 找不到对应文件时先手动释放资源,避免泄漏 fs.Dispose(); zip.Dispose(); return NotFound(); } string baseName = Path.GetFileName(entry.FullName); Stream entryStream = entry.Open(); // 将所有相关资源注册到响应释放队列,响应输出完成后自动释放 Response.RegisterForDispose(fs); Response.RegisterForDispose(zip); Response.RegisterForDispose(entryStream); // 直接返回条目流,不需要拷贝到内存 return File(entryStream, "application/octet-stream", baseName);
注意事项
- 该实现完全不会加载整个压缩包或者目标文件到内存,只会保留KB级别的解压缓冲区,内存占用极低,完全适配高并发下载场景
- 必须明确指定
ZipArchiveMode.Read模式打开压缩包,否则默认模式可能因为流权限问题导致读取失败 - 必须做目标条目判空处理,避免找不到文件时的空引用异常
- 所有用到的资源都要注册到
Response.RegisterForDispose,否则会出现文件句柄泄漏的问题
内容的提问来源于stack exchange,提问作者Johan Svensson
相关产品推荐
相关产品推荐

