通过命令行创建 7-Zip 存档时创建逻辑文件夹结构

问题描述

我一直使用“DotNetZip”库使用如下代码归档文件

var files = new []
{
    new { file = new FileInfo(@"C:\_test\Data\Testing\data.txt"),source = "Data" },new { file = new FileInfo(@"C:\_test\Logs\Testing\data.txt"),source = "Logs" },};  

using (Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile())
{
    zipFile.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
    foreach (var f in files)
    {
        zipFile.AddFile(f.file.FullName,f.source);
    }
    zipFile.Save(@"C:\_test\output.zip");
}

这里要注意的关键是文件名是相同的,它们直接包含在同名的文件夹中,当我创建 Zip 文件时,我正在为文件创建逻辑文件夹,以便在那里没有文件名冲突。

问题是 Zip 压缩很糟糕。事实上,我有一些例子说明我在其中放入一堆小文件并获得更大的 Zip!

然后我使用 7-Zip 进行了测试,结果非常好。文件大小比使用 Zip 小得多。

因此,我尝试使用 7-Zip 重写我的代码,但似乎没有适用于 .NET 的 7-Zip 库,唯一的选择是通过命令行使用 7-Zip。

我已经在 Powershell 中尝试过:

."C:\Program Files\7-Zip\7z.exe" a -mx9 "C:\_test\20210112 Testing.7z" "C:\_test\Data\Testing\data.txt" "C:\_test\Logs\Testing\data.txt"

但我得到这个输出

7-Zip 19.00 (x64) : copyright (c) 1999-2018 Igor Pavlov : 2019-02-21

Scanning the drive:
2 files,40 bytes (1 KiB)

Creating archive: C:\_test\__test.7z

ERROR:
Duplicate filename on disk:
data.txt
data.txt

如果我添加 -spf 命令行,那么它可以工作,但我的存档现在创建的每个文件夹都从 C 开始。

从命令行添加项目时,7-Zip 是否有办法允许它创建逻辑文件夹结构?

明确地说,我正在选择要存档的文件夹中的文件子集,并且我想将它们放在逻辑文件夹中。

解决方法

如果您只是想压缩文件夹中的所有内容,那么您可以这样做,它会保持文件夹结构。

."C:\Program Files\7-Zip\7z.exe" a -mx9 "C:\_test\20210112 Testing.7z" "C:\_test\*"

编辑:要选择性地存档某些文件,请使用相对路径。在您的情况下,您可以将 C:\_test 设置为当前目录,然后运行

."C:\Program Files\7-Zip\7z.exe" a -mx9 "C:\_test\20210112 Testing.7z" "Data\Testing\data.txt" "Logs\Testing\data.txt"
,

有趣的问题。我经常使用 7z,但从来不需要这样的工作流程。

正如您所知,由于存档中存在平面结构的重复文件,您会收到错误消息。 7z 存档器不知道使用哪个,因此出现错误。

我认为您很接近,但问题是您使用完全分类的路径来访问要打包的文件。

解决方案

您的解决方案是从 7z 运行 C:\_test\

"C:\Program Files\7-Zip\7z.exe" a -mx9 -spf2 "C:\_test\20210112_Testing.7z" "Data\Testing\data.txt" "Logs\Testing\data.txt"

现在您的存档将具有相同文件名的不同路径。我还建议不要在 7z 文件名中使用空格 - 您将来会省去麻烦。如果您有基于输入的相对或绝对路径,-spf2 开关将进行调整。如果我需要混合它,我倾向于把它放在那里。

注意

我喜欢使用 -spf2(不包括完整路径中的驱动器号)开关,因为这样可以在操作系统之间切换时更轻松。

,

我们使用来自代码的 SevenZipSharp NuGet 包。它具有 CompressFileDictionary 功能,可以添加字典中存在的所有文件,因此您可以挑选要添加的文件。

示例:

private void CreateArchive(string archivePath,Dictionary<string,string> materialsToArchive,int part)
{
    SevenZip.SevenZipCompressor.SetLibraryPath(Properties.Settings.Default.Location7zDll);
    SevenZip.SevenZipCompressor compressor = new SevenZip.SevenZipCompressor()
    {
        CompressionMode = part == 0 ? SevenZip.CompressionMode.Create : SevenZip.CompressionMode.Append,ArchiveFormat = SevenZip.OutArchiveFormat.Tar,CompressionMethod = SevenZip.CompressionMethod.Copy,CompressionLevel = SevenZip.CompressionLevel.None,IncludeEmptyDirectories = true,TempFolderPath = Path.GetDirectoryName(archivePath)
    };

    compressor.Compressing += new EventHandler<SevenZip.ProgressEventArgs>(CompressorCompressing);
    lastPercent = 0;
    firstTransfer = true;
    compressor.CompressFileDictionary(materialsToArchive,archivePath);
}

字典条目的 Key 是 zip 中的相对路径,Value 是文件的真实路径...

,

7-Zip 中有没有办法允许它创建一个逻辑文件夹 从命令行添加项目时的结构?

明确地说,我选择了文件夹中的文件子集作为 已存档,我想将它们放在逻辑文件夹中。

不幸的是,不,7-Zip 中没有这种方式。作者在 2015 年在他的 sourceforge site 上确认了这一点。从那时起,就没有 any update 这方面的内容。

内置的 PowerShell cmdlet Compress-Archive 也不支持这样的功能。


您只能通过一个明显的解决方法来实现这一点:临时创建逻辑文件夹结构,将文件复制到其中,存档此临时文件夹结构,然后将其删除。如果您想保留文件的时间戳 - 这将被常规复制操作更改 - 您可以使用 Robocopy.exe(Windows 已内置)与 /COPY:DAT /DCOPY:DAT 参数结合执行复制操作。