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

anr*_*eff 9 compression zip

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

zip a1.zip foo.dll
Run Code Online (Sandbox Code Playgroud)

我的测试 .dll 文件是 ~10MB,而存档结果是 3.5MB

然后创建一个内容完全相同的文件,并将它们放入存档中:

cp foo.dll bar.dll
zip a2.zip foo.dll bar.dll
Run Code Online (Sandbox Code Playgroud)

您可能期望 ZIP 足够聪明,可以确定这是重复数据,并且只使用 .zip 中的一个压缩对象,但事实并非如此:a2.zip 是 7.0MB!

基本上,大多数此类实用程序的行为相似(tar.gz、tar.bz2、rar 在solid 模式下)- 只有 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 中的另一个文件,则将其存储为引用(例如,通过使用--symlinks选项zip)。希望 Win32 下的解压缩程序能够支持这些并将文件副本提取到符号链接应位于的路径。Fe WinRAR 可以做到这一点,但是有很多“可以执行 .zip”的程序,我不确定是否都这样做。

Pra*_*eri 0

您可以通过编写一个小型的取消归档模块来解决您的问题。您可以将此解压缩器分发给用户,以便他们使用它来提取 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

            }

        }
Run Code Online (Sandbox Code Playgroud)

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

System.IO.File.Copy("source.dll", "destination.dll"); //IMPORTANT
Run Code Online (Sandbox Code Playgroud)

确保您包含开源 SharpZipLib DLL,这些是使用的命名空间:

using System;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
Run Code Online (Sandbox Code Playgroud)