首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DotNetZip从其他zip的子集创建zip

DotNetZip从其他zip的子集创建zip
EN

Stack Overflow用户
提问于 2011-10-31 20:13:50
回答 3查看 6.1K关注 0票数 3

我有一个大的zip文件,我需要分割成多个zip文件。在我现在创建的方法中,我有一个List对象。

这是我得到的密码:

代码语言:javascript
复制
 //All files have the same basefilename/
 string basefilename = Path.GetFileNameWithoutExtension(entries[0].FileName);
 MemoryStream memstream = new MemoryStream();
 ZipFile zip = new ZipFile();
 foreach (var entry in entries)
 {
    string newFileName = basefilename + Path.GetExtension(entry.FileName);
    zip.AddEntry(newFileName, entry.OpenReader());
 }

 zip.Save(memstream);

 //this will later go in an file-io handler class.
 FileStream outstream = File.OpenWrite(@"c:\files\"+basefilename+ ".zip");
 memstream.WriteTo(outstream);
 outstream.Flush();
 outstream.Close();

这就是我在save()调用时得到的错误:

{Ionic.Zlib.ZlibException:坏状态(无效块类型)在Ionic.Zlib.InflateManager.Inflate(FlushType刷新) at Ionic.Zlib.ZlibCodec.Inflate(FlushType刷新) at Ionic.Zlib.ZlibBaseStream.Read(Byte[]缓冲区,Int32偏移,Int32计数)在Ionic.Zlib.DeflateStream.Read(Byte[]缓冲区,Int32偏移,Int32计数)在Ionic.Crc.CrcCalculatorStream.Read(Byte[]缓冲区,Int32偏移,Int32计数)的Ionic.Zlib.DeflateStream.Read( Byte[]缓冲区,Int32偏移,Int32计数)的Ionic.Zlib.ZlibBaseStream.Read(Byte[]缓冲区,Int32偏移,Int32计数)的Ionic.Zlib.DeflateStream.Read(Byte[]缓冲区,Int32偏移,Int32计数)的Ionic.Crc.CrcCalculatorStream.Read(Byte[]缓冲区,Int32偏移,Int32计数)时,FlushType缓冲区,偏移,Int32 count,String FileName) at Ionic.Zip.ZipEntry._WriteEntryData(Stream s) at Ionic.Zip.ZipEntry.Write(Stream s) at Ionic.Zip.ZipFile.Save() at Ionic.Zip.ZipFile.Save(Stream outputStream) at

我做错了什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-10-31 21:33:17

下面是您所做的错误:在一个ZipEntry.OpenReader实例中有多个挂起的对ZipFile ()的调用。最多只能有一个挂起的ZipEntry.OpenReader()。

原因如下:当您使用ZipFile.Read()或新ZipFile()实例化给定的zip文件时,只创建一个Stream对象,传递现有文件的名称。当您调用ZipEntry.OpenReader()时,它会在Stream对象中生成一个查找(),将文件指针移动到该特定条目的压缩字节流的开头。当您再次调用ZipEntry.OpenReader()时,它会产生另一个call ()到流中的另一个位置。因此,通过连续添加条目并调用OpenReader(),您将多次调用will (),但只有最后一个调用才有效。流游标将放置在与最后一次调用ZipEntry.OpenReader()对应的条目的数据开始处。

要解决这个问题:放弃你的方法。与现有zip文件相比,创建新zip文件的最简单方法是:通过读取现有文件实例化zipfile,然后删除不需要的条目,然后将ZipFile.Save()调用到新路径。

代码语言:javascript
复制
using (var zip = ZipFile.Read("c:\\dir\\path\\to\\existing\\zipfile.zip")) 
{
    foreach (var name in namesToRemove) // IEnumerable<String>
    {
       zip[name].Remove();
    }
    zip.Save("c:\\path\\to\\new\\Archive.zip");
} 

编辑

在调用Save()时,库将读取未从文件系统文件中删除的条目的原始压缩数据,并将它们写入新的存档文件。这是非常快的,因为它不解压缩和重新压缩每个条目,以便将其放入新的、较小的zip文件中。基本上,它从原始zip文件中读取二进制数据片段,并将它们连接在一起形成新的、较小的zip文件。

要生成多个较小的文件,您可以在原始zip文件中重复这样做;只需将上面的文件包装在一个循环中,并更改您删除的文件以及新的、较小的归档的文件名。读取现有的fast文件也相当快。

作为替代,您可以解压缩和提取每个条目,然后将条目重新压缩并写入一个新的zip文件中。这是漫长的道路,但这是可能的。在这种情况下,对于您想要创建的每个较小的two文件,您将需要创建两个zipfile实例。通过读取原始zip存档打开第一个压缩文件。对于要保留的每个条目,创建一个MemoryStream,从条目中提取进入该MemoryStream的内容,并记住调用mem流中的want ()来重置内存流上的游标。然后使用第二个ZipFile实例调用AddEntry(),使用该MemoryStream作为添加条目的源。只在第二个实例上调用ZipFile.Save()。

代码语言:javascript
复制
using (var orig = ZipFile.Read("C:\\whatever\\OriginalArchive.zip"))
{
    using (var smaller = new ZipFile())
    {
      foreach (var name in entriesToKeep) 
      { 
         var ms = new MemoryStream();
         orig[name].Extract(ms); // extract into stream
         ms.Seek(0,SeekOrigin.Begin);
         smaller.AddEntry(name,ms);
      }
      smaller.Save("C:\\location\\of\\SmallerZip.zip");
    }   
}

这是可行的,但它需要对进入较小压缩区的每个条目进行解压缩和重新压缩,这是低效和不必要的。

如果您不介意解压缩和重新压缩的效率低下,那么可以使用另一种方法:调用ZipFile.AddEntry()重载,它接受开放程序和更接近的委托。这样做是将对OpenReader()的调用推迟到将条目写入新的、较小的zip文件的时候。其结果是一次只有一个挂起的OpenReader()。

代码语言:javascript
复制
using(ZipFile original = ZipFile.Read("C:\\path.to\\original\\Archive.zip"),
      smaller = new ZipFile())
{
    foreach (var name in entriesToKeep)
    {
        zip.AddEntry(zipEntryName,
                     (name) => original[name].OpenReader(),
                     null);
    }

    smaller.Save("C:\\path.to\\smaller\\Archive.zip");
}

它仍然是低效的,因为每个条目都会被解压缩和重新压缩,但是效率要低一点。

票数 8
EN

Stack Overflow用户

发布于 2011-11-01 08:51:55

Cheeso向我指出,我不能让多个读者打开。虽然他的移除方法不是我所需要的。所以我尝试用新的知识来解决问题,这就是我所创造的。

代码语言:javascript
复制
string basefilename = Path.GetFileNameWithoutExtension(entries[0].FileName);
ZipFile zip = new ZipFile();
foreach (var entry in entries){
      CrcCalculatorStream reader = entry.OpenReader();
      MemoryStream memstream = new MemoryStream();
      reader.CopyTo(memstream);
      byte[] bytes = memstream.ToArray();
      string newFileName = basefilename + Path.GetExtension(entry.FileName);
      zip.AddEntry(newFileName, bytes);
}

zip.Save(@"c:\files\" + basefilename + ".zip");
票数 1
EN

Stack Overflow用户

发布于 2011-10-31 20:45:13

编辑2:我认为在指定路径名时需要双反斜杠。我更新了我的代码以反映这一点。字符串中常规反斜杠的双反斜杠代码。

编辑:变量"newFileName“是否表示文件当前所在的路径?如果这个变量是其他变量,那么这可能是您的问题。没有看到更多的周围代码,我不确定。

我一直在代码中使用相同的库来生成.zips,但我从未像您所试图的那样做过。我不知道为什么您的代码会给您一个例外,但也许这会奏效吗?(假设您的字符串/路径名都是正确的,而zip库确实是造成问题的原因)

代码语言:javascript
复制
using (ZipFile zip = new ZipFile())
{
   zip.CompressionLevel = CompressionLevel.BestCompression;
   foreach (var entry in entries)
   {
      try
      {
         string newFileName = basefilename + Path.GetExtension(entry.FileName);
         zip.AddFile(newFileName, "");
      }
      catch (Exception) { }
   }
   zip.Save("c:\\files\\"+basefilename+ ".zip");
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7959211

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档