使用 ZipArchive 生成Zip文件备注

近两日研究了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:devStudyabpioabp_iosrcVolo.AbpWebSite.WebTemplateFiles"; 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