【问题标题】:Create normal zip file programmatically以编程方式创建普通 zip 文件
【发布时间】:2010-03-16 14:07:29
【问题描述】:

我看过很多关于如何在 c# 中压缩单个文件的教程。但我需要能够从一个以上的文件中创建一个普通的 *.zip 文件。 .NET 中有什么可以做到这一点吗?你有什么建议(记住我有严格的规定,不能使用其他库)

谢谢

【问题讨论】:

  • 使用 .NET 的 ZipArchive.CreateEntryFromFile 时,请注意您的参数,并确保您没有使用 entryName 参数的绝对路径。您不会收到任何警告,将生成 zip 文件,并且它将为空。如果您正在处理字符串而不是 .NET 的文件系统对象,则可以使用 Path.GetFileName(filePath),这将允许使用 obj.Name

标签: c# .net winforms compression zip


【解决方案1】:

只是为其他偶然发现此问题的人提供的更新。

从 .NET 4.5 开始,您可以使用 System.IO.Compression 将目录压缩为 zip 文件。您必须将System.IO.Compression.FileSystem 添加为引用,因为默认情况下不引用它。然后你可以写:

System.IO.Compression.ZipFile.CreateFromDirectory(dirPath, zipFile);

唯一的潜在问题是此程序集不适用于 Windows 应用商店应用程序。

【讨论】:

  • 也不支持密码保护。
【解决方案2】:

您现在可以使用 .NET 4.5 中提供的 ZipArchive 类 (System.IO.Compression.ZipArchive)

您必须添加System.IO.Compression 作为参考。

示例:生成 PDF 文件的 zip 文件

using (var fileStream = new FileStream(@"C:\temp\temp.zip", FileMode.CreateNew))
{
    using (var archive = new ZipArchive(fileStream, ZipArchiveMode.Create, true))
    {
        foreach (var creditNumber in creditNumbers)
        {
            var pdfBytes = GeneratePdf(creditNumber);
            var fileName = "credit_" + creditNumber + ".pdf";
            var zipArchiveEntry = archive.CreateEntry(fileName, CompressionLevel.Fastest);
            using (var zipStream = zipArchiveEntry.Open())
                zipStream.Write(pdfBytes, 0, pdfBytes.Length);
            }
        }
    }
}

【讨论】:

  • 如果您使用的是 VB.NET,获取文件字节的最快方法:My.Computer.FileSystem.ReadAllBytes(f)
【解决方案3】:

我的 2 美分:

    using (ZipArchive archive = ZipFile.Open(zFile, ZipArchiveMode.Create))
    {
        foreach (var fPath in filePaths)
        {
            archive.CreateEntryFromFile(fPath,Path.GetFileName(fPath));
        }
    }

所以 Zip 文件可以直接从文件/目录创建。

【讨论】:

  • @RodrigoStrauss 它是(目标,来源)
  • ZipArchive 来自什么参考? c#不认识它
  • ZipFile 和 ZipArchive 来自程序集 System.IO.Compression.FileSystem 和 System.IO.Compression
  • 此库仅适用于 .NET framework 4.5
  • 这对我来说是最简洁的答案。 +1
【解决方案4】:

编辑:如果您使用的是 .Net 4.5 或更高版本,这是built-in to the framework

对于早期版本或更多控制,您可以使用here on CodeProject by Gerald Gibson Jr 概述的 Windows 的 shell 函数。

我已将下面的文章文字照原样复制(原始许可:public domain

使用 Windows Shell API 和 C 压缩 Zip 文件

简介

这是我写的关于解压缩 Zip 文件的文章的后续文章。使用此代码,您可以使用 C# 中的 Windows Shell API 来压缩 Zip 文件,并且无需显示上面显示的“复制进度”窗口。通常,当您使用 Shell API 压缩 Zip 文件时,即使您设置选项告诉 Windows 不显示它,它也会显示“复制进度”窗口。为了解决这个问题,您将 Shell API 代码移动到一个单独的可执行文件,然后使用 .NET Process 类启动该可执行文件,确保将进程窗口样式设置为“隐藏”。

背景

曾经需要压缩 Zip 文件并且需要比许多免费压缩库提供的更好的 Zip? IE。您需要压缩文件夹和子文件夹以及文件。 Windows Zipping 可以压缩的不仅仅是单个文件。您所需要的只是一种以编程方式让 Windows 静默压缩这些 Zip 文件的方法。当然,您可以在其中一个商业 Zip 组件上花费 300 美元,但如果您只需要压缩文件夹层次结构,就很难免费获得。

使用代码

以下代码显示了如何使用 Windows Shell API 来压缩 Zip 文件。首先,您创建一个空的 Zip 文件。为此,请创建一个正确构造的字节数组,然后将该数组保存为扩展名为“.zip”的文件。我怎么知道要放入数组中的字节?好吧,我只是使用 Windows 创建了一个 Zip 文件,其中包含一个压缩文件。然后我用 Windows 打开 Zip 并删除了压缩文件。这给我留下了一个空的Zip。接下来,我在十六进制编辑器 (Visual Studio) 中打开空的 Zip 文件,查看十六进制字节值并使用 Windows Calc 将它们转换为十进制,并将这些十进制值复制到我的字节数组代码中。源文件夹指向您要压缩的文件夹。目标文件夹指向您刚刚创建的空 Zip 文件。此代码将按原样压缩 Zip 文件,但它也会显示“复制进度”窗口。要使此代码正常工作,您还需要设置对 COM 库的引用。在 References 窗口中,转到 COM 选项卡并选择标有“Microsoft Shell Controls and Automation”的库。

//Create an empty zip file
byte[] emptyzip = new byte[]{80,75,5,6,0,0,0,0,0, 
                  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

FileStream fs = File.Create(args[1]);
fs.Write(emptyzip, 0, emptyzip.Length);
fs.Flush();
fs.Close();
fs = null;

//Copy a folder and its contents into the newly created zip file
Shell32.ShellClass sc = new Shell32.ShellClass();
Shell32.Folder SrcFlder = sc.NameSpace(args[0]);
Shell32.Folder DestFlder = sc.NameSpace(args[1]); 
Shell32.FolderItems items = SrcFlder.Items();
DestFlder.CopyHere(items, 20);

//Ziping a file using the Windows Shell API 
//creates another thread where the zipping is executed.
//This means that it is possible that this console app 
//would end before the zipping thread 
//starts to execute which would cause the zip to never 
//occur and you will end up with just
//an empty zip file. So wait a second and give 
//the zipping thread time to get started
System.Threading.Thread.Sleep(1000);

本文包含的示例解决方案展示了如何将此代码放入控制台应用程序,然后启动此控制台应用程序以压缩 Zip,而不显示“复制进度”窗口。

下面的代码显示了一个按钮单击事件处理程序,其中包含用于启动控制台应用程序的代码,因此在压缩期间没有 UI:

private void btnUnzip_Click(object sender, System.EventArgs e)
{
    //Test to see if the user entered a zip file name
    if(txtZipFileName.Text.Trim() == "")
    {
        MessageBox.Show("You must enter what" + 
               " you want the name of the zip file to be");
        //Change the background color to cue the user to what needs fixed
        txtZipFileName.BackColor = Color.Yellow;
        return;
    }
    else
    {
        //Reset the background color
        txtZipFileName.BackColor = Color.White;
    }

    //Launch the zip.exe console app to do the actual zipping
    System.Diagnostics.ProcessStartInfo i =
        new System.Diagnostics.ProcessStartInfo(
        AppDomain.CurrentDomain.BaseDirectory + "zip.exe");
    i.CreateNoWindow = true;
    string args = "";

    
    if(txtSource.Text.IndexOf(" ") != -1)
    {
        //we got a space in the path so wrap it in double qoutes
        args += "\"" + txtSource.Text + "\"";
    }
    else
    {
        args += txtSource.Text;
    }

    string dest = txtDestination.Text;

    if(dest.EndsWith(@"\") == false)
    {
        dest += @"\";
    }

    //Make sure the zip file name ends with a zip extension
    if(txtZipFileName.Text.ToUpper().EndsWith(".ZIP") == false)
    {
        txtZipFileName.Text += ".zip";
    }

    dest += txtZipFileName.Text;

    if(dest.IndexOf(" ") != -1)
    {
        //we got a space in the path so wrap it in double qoutes
        args += " " + "\"" + dest + "\"";
    }
    else
    {
        args += " " + dest;
    }

    i.Arguments = args;
    

    //Mark the process window as hidden so 
    //that the progress copy window doesn't show
    i.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;    
    System.Diagnostics.Process p = System.Diagnostics.Process.Start(i);
    p.WaitForExit();
    MessageBox.Show("Complete");
}

【讨论】:

  • 谢谢@Stuart。非常感谢!
  • 从 .NET 4.5 开始,您可以使用 System.IO.Compression.ZipFile 完成此操作;更多详情请见this answer
【解决方案5】:

您可以考虑以下一些资源: Creating Zip archives in .NET (without an external library like SharpZipLib)

Zip Your Streams with System.IO.Packaging

我的建议和偏好是使用 system.io.packacking。这可以降低您的依赖关系(只是框架)。 Jgalloway 的帖子(第一个参考资料)提供了将两个文件添加到 zip 文件的一个很好的示例。是的,它更冗长,但您可以轻松创建外观(在某种程度上他的 AddFileToZip 做到了)。

HTH

【讨论】:

    【解决方案6】:

    你可以试试SharpZipLib。是开源的、平台无关的纯c#代码。

    【讨论】:

      【解决方案7】:

      .NET 具有用于压缩 System.IO.Compression 命名空间中的文件的内置功能。使用它,您不必将额外的库作为依赖项。 .NET 2.0 提供此功能。

      这是从我链接的 MSDN 页面进行压缩的方法:

          public static void Compress(FileInfo fi)
          {
              // Get the stream of the source file.
              using (FileStream inFile = fi.OpenRead())
              {
                  // Prevent compressing hidden and already compressed files.
                  if ((File.GetAttributes(fi.FullName) & FileAttributes.Hidden)
                          != FileAttributes.Hidden & fi.Extension != ".gz")
                  {
                      // Create the compressed file.
                      using (FileStream outFile = File.Create(fi.FullName + ".gz"))
                      {
                          using (GZipStream Compress = new GZipStream(outFile,
                                  CompressionMode.Compress))
                          {
                              // Copy the source file into the compression stream.
                              byte[] buffer = new byte[4096];
                              int numRead;
                              while ((numRead = inFile.Read(buffer, 0, buffer.Length)) != 0)
                              {
                                  Compress.Write(buffer, 0, numRead);
                              }
                              Console.WriteLine("Compressed {0} from {1} to {2} bytes.",
                                  fi.Name, fi.Length.ToString(), outFile.Length.ToString());
                          }
                      }
                  }
              }
      

      【讨论】:

      • 用于单个文件。如何处理多个文件
      【解决方案8】:

      你应该看看Zip Packages

      它们是普通 ZIP 存档的更结构化版本,需要在根目录中添加一些元数据。所以其他的ZIP工具可以打开一个包,但是Sysytem.IO.Packaging API不能打开所有的ZIP文件。

      【讨论】:

        【解决方案9】:

        这可以通过添加对 System.IO.Compression 和 System.IO.Compression.Filesystem 的引用来完成。

        示例 createZipFile() 方法可能如下所示:

        public static void createZipFile(string inputfile, string outputfile, CompressionLevel compressionlevel)
                {
                    try
                    {
                        using (ZipArchive za = ZipFile.Open(outputfile, ZipArchiveMode.Update))
                        {
                            //using the same file name as entry name
                            za.CreateEntryFromFile(inputfile, inputfile);
                        }
                    }
                    catch (ArgumentException)
                    {
                        Console.WriteLine("Invalid input/output file.");
                        Environment.Exit(-1);
                    }
        }
        

        在哪里

        • inputfile= 要压缩的文件名的字符串(为此 例如,您必须添加扩展名)
        • outputfile= 带有目标 zip 文件名的字符串

        More details about ZipFile Class in MSDN

        【讨论】:

          【解决方案10】:

          这是我在使用上述帖子后编写的一些代码。感谢你的帮助。

          此代码接受文件路径列表并从中创建一个 zip 文件。

          public class Zip
          {
              private string _filePath;
              public string FilePath { get { return _filePath; } }
          
              /// <summary>
              /// Zips a set of files
              /// </summary>
              /// <param name="filesToZip">A list of filepaths</param>
              /// <param name="sZipFileName">The file name of the new zip (do not include the file extension, nor the full path - just the name)</param>
              /// <param name="deleteExistingZip">Whether you want to delete the existing zip file</param>
              /// <remarks>
              /// Limitation - all files must be in the same location. 
              /// Limitation - must have read/write/edit access to folder where first file is located.
              /// Will throw exception if the zip file already exists and you do not specify deleteExistingZip
              /// </remarks>
              public Zip(List<string> filesToZip, string sZipFileName, bool deleteExistingZip = true)
              {
                  if (filesToZip.Count > 0)
                  {
                      if (File.Exists(filesToZip[0]))
                      {
          
                          // Get the first file in the list so we can get the root directory
                          string strRootDirectory = Path.GetDirectoryName(filesToZip[0]);
          
                          // Set up a temporary directory to save the files to (that we will eventually zip up)
                          DirectoryInfo dirTemp = Directory.CreateDirectory(strRootDirectory + "/" + DateTime.Now.ToString("yyyyMMddhhmmss"));
          
                          // Copy all files to the temporary directory
                          foreach (string strFilePath in filesToZip)
                          {
                              if (!File.Exists(strFilePath))
                              {
                                  throw new Exception(string.Format("File {0} does not exist", strFilePath));
                              }
                              string strDestinationFilePath = Path.Combine(dirTemp.FullName, Path.GetFileName(strFilePath));
                              File.Copy(strFilePath, strDestinationFilePath);
                          }
          
                          // Create the zip file using the temporary directory
                          if (!sZipFileName.EndsWith(".zip")) { sZipFileName += ".zip"; }
                          string strZipPath = Path.Combine(strRootDirectory, sZipFileName);
                          if (deleteExistingZip == true && File.Exists(strZipPath)) { File.Delete(strZipPath); }
                          ZipFile.CreateFromDirectory(dirTemp.FullName, strZipPath, CompressionLevel.Fastest, false);
          
                          // Delete the temporary directory
                          dirTemp.Delete(true);
          
                          _filePath = strZipPath;                    
                      }
                      else
                      {
                          throw new Exception(string.Format("File {0} does not exist", filesToZip[0]));
                      }
                  }
                  else
                  {
                      throw new Exception("You must specify at least one file to zip.");
                  }
              }
          }
          

          【讨论】:

            【解决方案11】:

            这可以通过仅使用 Dot Net 的一行代码来完成。下面是从MSDN复制的示例代码

            第 1 步:添加对 System.IO.Compression.FileSystem 的引用

            第 2 步:按照下面的代码进行操作

                    static void Main(string[] args)
                    {
                        string startPath = @"c:\example\start";
                        string zipPath = @"c:\example\result.zip";
                        string extractPath = @"c:\example\extract";
            
                        ZipFile.CreateFromDirectory(startPath, zipPath);
            
                        ZipFile.ExtractToDirectory(zipPath, extractPath);
                    }
            

            【讨论】:

            • 这只会创建你需要使用 ZipArchive 的空 zip
            猜你喜欢
            • 2017-05-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-26
            • 2011-01-18
            • 2010-12-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多