在C#的.NET Core Lambda中从现有Zip生成指定子目录Zip的问题
解决Lambda下Zip处理的临时存储问题
首先,咱们先拆解下问题的核心:
- 你遇到的路径错误,是因为
CreateEntryFromFile方法会去本地文件系统找文件,但你的目标文件实际在原Zip包的流里,并不是本地磁盘上的文件 - 原来的
Concat操作根本没生效,因为它返回新集合而不是修改原集合,导致bat/yml文件根本没被加入打包列表 - 需要正确映射原Zip条目到新Zip里的路径,才能满足“把根目录文件移到Svr1目录再打包”的需求
下面是修正后的完整代码,我会逐段解释关键修复点:
var tempPath = @"/tmp/"; var sourceZipPath = Path.Combine(tempPath, "MyZipFile.zip"); var targetZipPath = Path.Combine(tempPath, "Svr1.zip"); // 读取原Zip包 using (var sourceFileStream = File.OpenRead(sourceZipPath)) using (var sourceZip = new ZipArchive(sourceFileStream, ZipArchiveMode.Read, true)) { // 筛选需要包含的条目: // 1. Env/Svr1下的所有文件(排除目录条目,因为Zip里的目录条目Name为空) var svr1Entries = sourceZip.Entries .Where(entry => entry.FullName.StartsWith("Env/Svr1/", StringComparison.Ordinal) && !string.IsNullOrEmpty(entry.Name)); // 2. 根目录下的scripts.bat和scripts2.yml var rootFiles = sourceZip.Entries .Where(entry => entry.Name is "scripts.bat" or "scripts2.yml"); // 合并所有需要打包的条目 var allEntriesToPackage = svr1Entries.Concat(rootFiles); // 创建目标Zip包(用Create模式,Lambda的/tmp目录每次都是全新的,不需要Update) using (var targetFileStream = File.Create(targetZipPath)) using (var targetZip = new ZipArchive(targetFileStream, ZipArchiveMode.Create)) { foreach (var entry in allEntriesToPackage) { // 确定条目在新Zip里的路径: string entryPathInTarget; if (entry.FullName.StartsWith("Env/Svr1/", StringComparison.Ordinal)) { // 去掉Env/Svr1/前缀,让原Svr1下的文件在新Zip里处于根目录 entryPathInTarget = entry.FullName.Substring("Env/Svr1/".Length); } else { // 根目录的bat/yml直接用文件名,相当于把它们"移动"到Svr1目录下 entryPathInTarget = entry.Name; } // 创建新Zip里的条目 var targetEntry = targetZip.CreateEntry(entryPathInTarget, CompressionLevel.Optimal); // 直接从原Zip条目读取流,写入新条目——完全不需要解压到本地磁盘 using (var sourceStream = entry.Open()) using (var targetStream = targetEntry.Open()) { await sourceStream.CopyToAsync(targetStream); // 异步操作更适配Lambda环境 } } } }
关键修复点说明:
彻底解决路径错误:
不再依赖CreateEntryFromFile读取本地文件,而是直接操作Zip条目流——通过entry.Open()读取原Zip里的文件内容,再写入新Zip的条目流中,全程不需要解压整个300MB的包到本地磁盘,完美适配Lambda的512MB临时存储限制。修复集合合并失效问题:
原来的svr1Folder.Concat(...)只是返回新集合但没赋值,导致bat/yml文件根本没被加入打包列表。现在我们把svr1Entries和rootFiles合并成allEntriesToPackage,确保所有需要的文件都被包含。正确映射文件路径:
- 原
Env/Svr1下的文件去掉前缀,在新Zip里处于根目录(对应“压缩Svr1目录内容”的需求) - 根目录的bat/yml直接用文件名,相当于把它们“移动”到Svr1目录下再打包。
- 原
Lambda环境适配优化:
- 使用异步的
CopyToAsync方法,避免阻塞线程,更适合无服务器环境 - 用
File.Create创建目标Zip,因为Lambda的/tmp目录每次调用都是全新的,不需要更新现有文件
- 使用异步的
这样处理后,整个过程完全在流之间操作,只占用必要的内存和临时存储来生成新的Svr1.zip,完美解决你的存储限制问题。
内容的提问来源于stack exchange,提问作者Sat
相关产品推荐
相关产品推荐

