近两日研究了Abp.io 中模板项目的生成原理,是从Github下载源码包,进行修改、替换,然后生成新的zip包提供下载。
项目内部使用了 这个包 Ionic.Zip Version="1.9.1.8“ ,这个包 不支持 .NetCore 。
无法编译,项目文件中有: <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
但还不清楚是什么作用。
报着学习的态度,尝试替换 Ionic.Zip 替换为 ZipArchive .官网上看了看文档,还比较顺利。。 也能生成Zip ,但生成的Zip始终报错,”文件末端错误 “。 只能一个一个步骤找原因。
这个是直接读,直接写,没有问题。---
1 public static void TestReadZipAndWriteToNewZip() 2 { 3 string path = @"D:\dev\Study\abpio\abp_io\src\Volo.AbpWebSite.Web\TemplateFiles\"; 4 string srcFile = path + "test.zip"; 5 string destFile = path + "test_dest.zip"; 6 7 using (var readStream = File.OpenRead(srcFile)) 8 { 9 using (var archive = new ZipArchive(readStream, ZipArchiveMode.Read)) 10 { 11 using (var writeFileStream = new FileStream(destFile, FileMode.CreateNew)) 12 { 13 using (var outZip = new ZipArchive(writeFileStream, ZipArchiveMode.Create)) 14 { 15 foreach (var entry_item in archive.Entries) 16 { 17 var new_entry = outZip.CreateEntry(entry_item.FullName); 18 using (var stream = new_entry.Open()) 19 { 20 entry_item.Open().CopyTo(stream); 21 } 22 } 23 24 } 25 } 26 27 } 28 } 29 }
里边可以注意到多层包裹,整个Zip要有Stream .内部的ZipArctiveEntry也要有留的。
从 ZipArctiveEntry 中读取 内容到字节数组
public static byte[] GetBytes(this ZipArchiveEntry zipFile) { using (var ms = new MemoryStream()) { using (var stream = zipFile.Open()) { stream.CopyTo(ms); return ms.ToArray(); } } }
转换为可以处理的 内存文件列表
public static FileEntryList ToFileEntryList(this ZipArchive zipFile, string rootFolder = null) { var zipEntries = zipFile.Entries.ToList(); if (rootFolder != null) { zipEntries = zipFile.Entries.Where(entry => entry.FullName.StartsWith(rootFolder)).ToList(); } var fileEntries = new List<FileEntry>(); foreach (var zipEntry in zipEntries) { var fileName = zipEntry.FullName; if (rootFolder != null) { fileName = fileName.RemovePreFix(rootFolder); } if (fileName.IsNullOrEmpty()) { continue; } fileEntries.Add(new FileEntry(fileName, zipEntry.GetBytes(), zipEntry.IsDirectory()); } return new FileEntryList(fileEntries); }
private static FileEntryList GetEntriesFromZipFile(string filePath, string rootFolder = null) { using (var templateFileStream = File.OpenRead(filePath)) { using (var archive = new ZipArchive(templateFileStream, ZipArchiveMode.Read)) { return archive.ToFileEntryList(rootFolder); } } }
private static byte[] CreateZipFileFromEntries(FileEntryList entries) { using (var stream = new MemoryStream()) { using (var resultZipFile = new ZipArchive(stream,ZipArchiveMode.Create)) { entries.CopyToZipFile(resultZipFile); }
//重点在这里: 生成的Zip的流数据返回,一定要在 ZipArchive 的生存期外边!!!!
//如果是直接 写入 FileStream 无所谓 。但要作为 Byte[] 返回 一定要等到释放,或者说,完成压缩后。
//猜测是 在销毁的时候写入Stream的, 没有看到 ZipArchive 的源码,只能猜测。
return stream.ToArray();
}
}
虽然花费了不少时间,但总算解决了,~~~~
原文:https://www.cnblogs.com/abin30/p/10562090.html