使用密码在.NET中创建zip文件

create zip file in .net with password

提问人:Reza Akraminejad 提问时间:5/4/2016 最后编辑:McMillan ChengReza Akraminejad 更新时间:3/23/2023 访问量:65530

问:

我正在处理一个项目,我需要创建一个 zip 文件,密码受 c# 中文件内容的影响。

在我使用 System.IO.Compression.GZipStream 创建 gzip 内容之前。 .net 是否有任何功能来创建受 zip 或 rar 密码保护的文件?

C# .NET 密码 zip dotnetzip

评论

1赞 VitaliyK 5/4/2016
一般来说,如果System.IO.Compression.GZipStream的功能对你来说还不够 - 有一个框架 sevenzipsharp.codeplex.com 它要复杂得多。在 .net 框架中,GZipStream 是创建存档的唯一方法。
0赞 Manfred Radlwimmer 5/4/2016
@VitaliyK 我也推荐 7Zip#,但除了 、 、 (自 4.5 起)等之外,框架中还有其他一些压缩机制GZipStreamDeflateStreamZipPackageZipFile
0赞 Reza Akraminejad 5/4/2016
gzipstream @VitaliyK具有密码功能?我没有找到任何类型的密码功能
0赞 VitaliyK 5/4/2016
@Hamed_gibago 不可以,您不能使用 GZipStream 使用密码保护 arcive。您需要使用另一个 zip 框架(7Zip、DotNetZip 等)。

答:

8赞 Manfred Radlwimmer 5/4/2016 #1

不幸的是,框架中没有这样的功能。有一种方法可以制作ZIP文件,但没有密码。如果你想在C#中创建受密码保护的ZIP文件,我推荐SevenZipSharp。它基本上是 7-Zip 的托管包装器。

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);
}

评论

0赞 frankhommers 9/4/2019
不幸的是,这个解决方案只是Windows,因为它依赖于7za.dll。其他解决方案跨平台工作。
15赞 Jan Wiesemann 5/4/2016 #2

看看 DotNetZip(@AFract在评论中提供了指向 GitHub 的新链接)

它有相当多的文档,它还允许您在运行时将 dll 加载为嵌入文件。

评论

0赞 Paul 7/10/2018
我已经下载了这个,但在下载中找不到要在我的项目中使用的 DLL。
0赞 StayOnTarget 8/8/2018
这还在维护吗?原始项目有一个 github 分支,但自从 CodePlex 关闭以来,我经常不确定此类项目的状态
2赞 Jan Wiesemann 8/9/2018
nuget.org/packages/DotNetZip“3个月前的最后更新”我认为它仍然保持。
0赞 AFract 1/27/2020
绑定到 nuget 包的 github 存储库: github.com/haf/DotNetZip.Semverd 不要看 codeplex,它(显然)已经过时了,因为 Codeplex 已经死了。
0赞 Demodave 5/1/2020
请举例说明
5赞 testing 7/18/2018 #3

我想添加更多替代方案。

对于 .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;
}

更多示例可以在这里找到。

如果您可以不使用密码功能,则可以提及 ZipStorerSystem.IO.Compression 中的内置 .NET 函数。

6赞 LCJ 12/15/2020 #4

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");
        }
 }

评论

0赞 Paul Efford 3/15/2023
它创建了一个 zip,您可以在其中查看其中的文件;要打开其中任何一个,您将被要求输入密码。有趣的是,您可以提取zip并获取其中的所有文件......无需输入任何密码!所以。。。这个“密码”功能的真正用例是什么?
0赞 Paul Efford 3/23/2023 #5

我发现有两个选项是可靠且易于使用的,具体取决于允许您在项目中使用的许可证类型。

第一个是:

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 文件夹,其中将需要密码来提取文件(如果您在调用该方法时设置了它)。