我正在进行一个项目,需要使用C#从文件内容创建密码保护的zip文件。
之前我使用System.IO.Compression.GZipStream来创建gzip内容。 在.NET中有没有功能可以创建密码保护的zip或rar文件呢?
请看DotNetZip(@AFract在评论中提供了新的GitHub链接)。
它有非常好的文档,并且还允许您将dll作为嵌入式文件在运行时加载。
SevenZipBase.SetLibraryPath(Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Environment.CurrentDirectory,
"7za.dll"));
SevenZipCompressor compressor = new SevenZipCompressor();
compressor.Compressing += Compressor_Compressing;
compressor.FileCompressionStarted += Compressor_FileCompressionStarted;
compressor.CompressionFinished += Compressor_CompressionFinished;
string password = @"whatever";
string destinationFile = @"C:\Temp\whatever.zip";
string[] sourceFiles = Directory.GetFiles(@"C:\Temp\YourFiles\");
if (String.IsNullOrWhiteSpace(password))
{
compressor.CompressFiles(destinationFile, sourceFiles);
}
else
{
//optional
compressor.EncryptHeaders = true;
compressor.CompressFilesEncrypted(destinationFile, password, sourceFiles);
}
DotNetZip 在使用上非常顺畅且干净。
DotNetZip is a FAST, FREE class library and toolset for manipulating zip files.
代码
static void Main(string[] args)
{
using (ZipFile zip = new ZipFile())
{
zip.Password = "mypassword";
zip.AddDirectory(@"C:\Test\Report_CCLF5\");
zip.Save(@"C:\Test\Report_CCLF5_PartB.zip");
}
}
我希望能提供更多的替代方案。
对于.NET,可以使用SharpZipLib,对于Xamarin,则可使用SharpZipLib.Portable。
.NET的示例:
using ICSharpCode.SharpZipLib.Zip;
// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,
// which is returned as a memory stream or a byte array.
//
public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {
MemoryStream outputMemStream = new MemoryStream();
ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);
zipStream.SetLevel(3); //0-9, 9 being the highest level of compression
zipStream.Password = "Your password";
ZipEntry newEntry = new ZipEntry(zipEntryName);
newEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(newEntry);
StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
zipStream.CloseEntry();
zipStream.IsStreamOwner = false; // False stops the Close also Closing the underlying stream.
zipStream.Close(); // Must finish the ZipOutputStream before using outputMemStream.
outputMemStream.Position = 0;
return outputMemStream;
// Alternative outputs:
// ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
byte[] byteArrayOut = outputMemStream.ToArray();
// GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.
byte[] byteArrayOut = outputMemStream.GetBuffer();
long len = outputMemStream.Length;
}
更多示例可以在这里找到。
如果您可以不使用密码功能,可以提及ZipStorer或内置在System.IO.Compression
中的.NET函数。
我发现有两个选项是可靠且易于使用的,具体取决于您在项目中被允许使用的许可证类型。
第一个选项是:
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
namespace DataReader.zip
{
internal static class Zip1 // SharpZipLib nuget lib, MIT free license
{
public static bool Create(string destZipPath, string folderToCompress, string? password = null, int compressionLevel = 3)
{
bool res;
try
{
var fsOut = File.Create($"{destZipPath}.zip"); // ending '.zip' is a must!
var zipStream = new ZipOutputStream(fsOut);
zipStream.SetLevel(compressionLevel); // 0-9, 9 being the highest level of compression
zipStream.Password = password; // optional. Null is the same as not setting. Required if using AES.
// This setting will strip the leading part of the folder path in the entries, to
// make the entries relative to the starting folder.
// To include the full path for each entry up to the drive root, assign folderOffset = 0.
var folderOffset = folderToCompress.Length + (folderToCompress.EndsWith("\\") ? 0 : 1);
res = CompressFolder(folderToCompress, zipStream, folderOffset);
zipStream.IsStreamOwner = true; // Makes the Close also Close the underlying stream
zipStream.Close();
return res;
}
catch (Exception e)
{
return Console.WriteLine($"{e.Message}: {destZipPath}");
}
}
private static bool CompressFolder(string path, ZipOutputStream zipStream, int folderOffset)
{
try
{
var files = Directory.GetFiles(path);
if (files.Length == 0)
{
Message.Show($"Warning: no files to compress found in folder '{path}'");
return false;
}
foreach (var filename in files)
{
var fi = new FileInfo(filename);
var entryName = filename.Substring(folderOffset); // Makes the name in zip based on the folder
entryName = ZipEntry.CleanName(entryName); // Removes drive from name and fixes slash direction
var newEntry = new ZipEntry(entryName);
newEntry.DateTime = fi.LastWriteTime; // Note the zip format stores 2 second granularity
// Specifying the AESKeySize triggers AES encryption. Allowable values are 0 (off), 128 or 256.
// A password on the ZipOutputStream is required if using AES.
// newEntry.AESKeySize = 256;
// To permit the zip to be unpacked by built-in extractor in WinXP and Server2003, WinZip 8, Java, and other older code,
// you need to do one of the following: Specify UseZip64.Off, or set the Size.
// If the file may be bigger than 4GB, or you do not need WinXP built-in compatibility, you do not need either,
// but the zip will be in Zip64 format which not all utilities can understand.
zipStream.UseZip64 = UseZip64.On;
newEntry.Size = fi.Length;
zipStream.PutNextEntry(newEntry);
// Zip the file in buffered chunks
// the "using" will close the stream even if an exception occurs
var buffer = new byte[4096];
using (var streamReader = File.OpenRead(filename))
{
StreamUtils.Copy(streamReader, zipStream, buffer);
}
zipStream.CloseEntry();
}
return true;
}
catch (Exception e)
{
return Console.WriteLine($"{e.Message}: {destZipPath}");
}
}
}
}
还有第二个:
using Ionic.Zip;
namespace DataReader.zip
{
internal class Zip2 // DotNetZip nuget lib
{
public static bool Create(string destZipPath, string folderToCompress, string? password = null, int compressionLevel = 3)
{
try
{
using ZipFile zip = new();
if (password != null)
zip.Password = password;
zip.CompressionLevel = (Ionic.Zlib.CompressionLevel)compressionLevel;
zip.AddDirectory(folderToCompress);
zip.Save($"{destZipPath}.zip");
return true;
}
catch (Exception e)
{
return Console.WriteLine($"{e.Message}: {destZipPath}");
}
}
}
}
使用这两个选项,您将创建一个zip文件夹,在提取文件时需要输入密码(如果在调用方法时设置了密码)。
GZipStream
之外,框架中还有其他的压缩机制(例如DeflateStream
、ZipPackage
、ZipFile
(自4.5版本以来)等)。 - Manfred Radlwimmer