将两个相同的文件放入 .zip 中时,它们会占用 2 倍空间,可以避免这种情况吗

将两个相同的文件放入 .zip 中时,它们会占用 2 倍空间,可以避免这种情况吗

假设您有一个想要放入 .zip 存档的文件:

zip a1.zip foo.dll

我的测试 .dll 文件大约 10MB,而存档文件只有 3.5MB

然后创建一个具有完全相同内容的文件,并将这两个文件放入档案中:

cp foo.dll bar.dll
zip a2.zip foo.dll bar.dll

您可能认为 ZIP 足够智能,可以找出重复数据并仅使用 .zip 内的一个压缩对象,但事实并非如此:a2.zip 是 7.0MB!

基本上大多数此类实用程序的行为都类似(tar.gz,tar.bz2,rar处于稳定模式) - 只有 7zip 捕获了我并且生成的 a2.7z 仅比 a1.7z 略大。

所以问题是:是否可以构建一个 .zip 文件来避免这种空间浪费? 我们使用 C++ 代码创建 .zip 文件,该代码使用了来自 zlib 的 minizip 项目。


我们为什么需要这个?

我们以“.exe 安装程序”和“.zip 文件”两种形式提供软件。该软件实际上不需要安装,您只需解压即可使用。拥有许多工作站并使用自动部署/软件更新服务的大型客户更喜欢 .zip 选项。

我们最近引入了三个 .dll 文件,现在需要将它们放在两个不同的文件夹中,以供不同的组件使用(由于技术原因,这些文件无法只放在一个中心目录中)。这三个 .dll 文件在两个文件夹中都是完全相同的副本。.exe 安装程序可以解决这个问题,因为我们指示它对两个目标使用完全相同的压缩 blob。但 .zip 并非如此,最终的安装会大 15MB,这意味着更多的带宽使用、更慢的下载时间和工程师因事情不理想而产生的愤怒。此外,.zip 安装突然变得比 .exe 安装大,所以我们会被问到我们在 .exe 安装中省略了什么。

有一些潜在的解决方案,

  • 使用 7-zip:但是老板强烈反对这样做,因为这会迫使前面提到的自动部署人员修改他们的脚本以适应 7-zip。
  • 使用符号链接:如果您在 .zip 中放置一个符号链接,该符号链接指向 .zip 中的另一个文件,它将被存储为引用(例如,通过使用选项--symlinkszip。希望 Win32 下的解压程序能够支持这些,并将文件的副本提取到符号链接所在的路径。虽然 WinRAR 可以做到这一点,但有很多程序“可以执行 .zip”,我不确定是否所有程序都这样做。

答案1

您可以将这两个文件放入一个未压缩的 zip 文件中(例如使用 7-Zip),然后将生成的文件再次放入 zip 文件中。

答案2

您可以通过编写一个小型解压模块来解决问题。您可以将此解压程序分发给用户,以便他们使用它来提取 zip,或者更好的是,将该模块作为 .EXE 程序本身的一部分实现。该模块可以是 C# 控制台程序,如下所示:

        private static void Extract(string filename)
        {
            //ZipInputStream zi = new ZipInputStream (File.Open ("", FileMode.Open));
            using (ZipInputStream s = new ZipInputStream(File.OpenRead(filename))) {

                ZipEntry theEntry=null;
                while ((theEntry = s.GetNextEntry()) != null) 
                {

                    Console.WriteLine(theEntry.Name);

                    string directoryName = Path.GetDirectoryName(basedir + "ext" + Path.DirectorySeparatorChar + theEntry.Name);
                    string fileName = Path.GetFileName(basedir + "ext" + Path.DirectorySeparatorChar  + theEntry.Name);
                    Console.WriteLine("And the path is:" + basedir +  "ext" + Path.DirectorySeparatorChar  + theEntry.Name);

// create directory
                    if ( directoryName.Length > 0 ) {
                        //Console.WriteLine("DIRECTORY IS SOMETHING");
                        Directory.CreateDirectory(directoryName);
                    }

                    if (fileName != String.Empty) {
                        using (FileStream streamWriter = File.Create(basedir+"DLL_PATH" + Path.DirectorySeparatorChar  + theEntry.Name)) {

                            int size = 2048;
                            byte[] data = new byte[2048];
                            while (true) {
                                size = s.Read(data, 0, data.Length);
                                if (size > 0) {
                                    streamWriter.Write(data, 0, size);
                                } else {
                                    break;
                                }
                            }
                        }
                    }
                }
                  System.IO.File.Copy("source.dll", "destination.dll"); //IMPORTANT

            }

        }

这尚未经过测试,但我确信您可以使用它。最重要的部分是将提取的文件复制到新的 dll:

System.IO.File.Copy("source.dll", "destination.dll"); //IMPORTANT

确保将开源 SharpZipLib DLL 包含在内,并且这些是使用的命名空间:

using System;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Xml;

答案3

我提出两种方案:

  • 分发自解压文件.exe(不是安装程序),它会创建一个目录,其中所有文件都位于正确的相对位置(然后客户端只需将目录拖放到他想要的位置)。如果您使用 7zip 创建它,您将拥有占用空间较小的优势,此外,如果人们安装了 7zip,它可以作为存档由 7zip 本身打开。
  • 拥抱简单,坚持.zip使用重复文件。带宽真的有那么大的问题吗?用户抱怨东西无法按预期工作/无法执行复杂的安装过程难道不是更大的麻烦吗?从客户的角度来看,这可能不是问题:16 MB 通常不会超过 1 分钟的下载时间,而且他们不必每天都下载相同的文件。当然,这取决于整个安装程序的大小:如果差异在 5 MB 和 21 MB 之间,我也会担心。

相关内容