问题描述
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
参数结合执行复制操作。