【问题标题】:Zip subfolders using ZipOutputStream使用 ZipOutputStream 压缩子文件夹
【发布时间】:2011-01-19 09:41:17
【问题描述】:

ZipOutputStream 仅压缩文件夹中的文件。我也想压缩子文件夹。我怎样才能做到这一点?

【问题讨论】:

  • 我希望您没有放弃这个问题,并且会回来标记答案或至少指出哪些答案有帮助。在您的 200 多个问题中,您将有大约 120 个需要标记答案(如果答案令人满意),每个标记的答案将为您赢得额外的 2 个代表点,并帮助您问题的未来查看者知道最佳答案是什么. 120 * 2rep = 240 rep 你可以获得。

标签: c# .net zipoutputstream


【解决方案1】:

您必须递归浏览您的目录才能将所有文件添加到 zip 中。

如果您愿意,请查看这个小助手:

 using ICSharpCode.SharpZipLib.Zip;
    using ICSharpCode.SharpZipLib.Checksums;
    using System.IO;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Collections;
    using System.Text.RegularExpressions;

   namespace Zip
{
    /// <summary>
    /// Uses Sharpziplib so as to create a non flat zip archive
    /// </summary>
    public abstract class ZipManager
    {
        /// <summary>
        /// will zip directory .\toto as .\toto.zip
        /// </summary>
        /// <param name="stDirToZip"></param>
        /// <returns></returns>
        public static string CreateZip(string stDirToZip)
        {
            try
            {
                DirectoryInfo di = new DirectoryInfo(stDirToZip);
                string stZipPath = di.Parent.FullName + "\\" + di.Name + ".zip";

                CreateZip(stZipPath, stDirToZip);

                return stZipPath;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Main method
        /// </summary>
        /// <param name="stZipPath">path of the archive wanted</param>
        /// <param name="stDirToZip">path of the directory we want to create, without ending backslash</param>
        public static void CreateZip(string stZipPath, string stDirToZip)
        {
            try
            {
                //Sanitize inputs
                stDirToZip = Path.GetFullPath(stDirToZip);
                stZipPath = Path.GetFullPath(stZipPath);

                Console.WriteLine("Zip directory " + stDirToZip);

                //Recursively parse the directory to zip 
                Stack<FileInfo> stackFiles = DirExplore(stDirToZip);

                ZipOutputStream zipOutput = null;

                if (File.Exists(stZipPath))
                    File.Delete(stZipPath);

                Crc32 crc = new Crc32();
                zipOutput = new ZipOutputStream(File.Create(stZipPath));
                zipOutput.SetLevel(6); // 0 - store only to 9 - means best compression

                Console.WriteLine(stackFiles.Count + " files to zip.\n");

                int index = 0;
                foreach (FileInfo fi in stackFiles)
                {
                    ++index;
                    int percent = (int)((float)index / ((float)stackFiles.Count / 100));
                    if (percent % 1 == 0)
                    {
                        Console.CursorLeft = 0;
                        Console.Write(_stSchon[index % _stSchon.Length].ToString() + " " + percent + "% done.");
                    }
                    FileStream fs = File.OpenRead(fi.FullName);

                    byte[] buffer = new byte[fs.Length];
                    fs.Read(buffer, 0, buffer.Length);

                    //Create the right arborescence within the archive
                    string stFileName = fi.FullName.Remove(0, stDirToZip.Length + 1);
                    ZipEntry entry = new ZipEntry(stFileName);

                    entry.DateTime = DateTime.Now;

                    // set Size and the crc, because the information
                    // about the size and crc should be stored in the header
                    // if it is not set it is automatically written in the footer.
                    // (in this case size == crc == -1 in the header)
                    // Some ZIP programs have problems with zip files that don't store
                    // the size and crc in the header.
                    entry.Size = fs.Length;
                    fs.Close();

                    crc.Reset();
                    crc.Update(buffer);

                    entry.Crc = crc.Value;

                    zipOutput.PutNextEntry(entry);

                    zipOutput.Write(buffer, 0, buffer.Length);
                }
                zipOutput.Finish();
                zipOutput.Close();
                zipOutput = null;
            }
            catch (Exception)
            {
                throw;
            }
        }


        static private Stack<FileInfo> DirExplore(string stSrcDirPath)
        {
            try
            {
                Stack<DirectoryInfo> stackDirs = new Stack<DirectoryInfo>();
                Stack<FileInfo> stackPaths = new Stack<FileInfo>();

                DirectoryInfo dd = new DirectoryInfo(Path.GetFullPath(stSrcDirPath));

                stackDirs.Push(dd);
                while (stackDirs.Count > 0)
                {
                    DirectoryInfo currentDir = (DirectoryInfo)stackDirs.Pop();

                    try
                    {
                        //Process .\files
                        foreach (FileInfo fileInfo in currentDir.GetFiles())
                        {
                            stackPaths.Push(fileInfo);
                        }

                        //Process Subdirectories
                        foreach (DirectoryInfo diNext in currentDir.GetDirectories())
                            stackDirs.Push(diNext);
                    }
                    catch (Exception)
                    {//Might be a system directory
                    }
                }
                return stackPaths;
            }
            catch (Exception)
            {
                throw;
            }
        }

        private static char[] _stSchon = new char[] { '-', '\\', '|', '/' };
    }
}

【讨论】:

  • 这不会压缩子文件夹,我想在压缩包中添加文件夹。
  • 你试过这个代码吗?它可以很好地压缩子文件夹(参见 DirExplore 方法)
  • 请注意,它不会压缩空目录。
【解决方案2】:
public static void ZipDirectoryKeepRelativeSubfolder(string zipFilePath, string directoryToZip)
{
    var filenames = Directory.GetFiles(directoryToZip, "*.*", SearchOption.AllDirectories);
    using (var s = new ZipOutputStream(File.Create(zipFilePath)))
    {
        s.SetLevel(9);// 0 - store only to 9 - means best compression

        var buffer = new byte[4096];

        foreach (var file in filenames)
        {
            var relativePath = file.Substring(directoryToZip.Length).TrimStart('\\');
            var entry = new ZipEntry(relativePath);
            entry.DateTime = DateTime.Now;
            s.PutNextEntry(entry);

            using (var fs = File.OpenRead(file))
            {
                int sourceBytes;
                do
                {
                    sourceBytes = fs.Read(buffer, 0, buffer.Length);
                    s.Write(buffer, 0, sourceBytes);
                } while (sourceBytes > 0);
            }
        }
        s.Finish();
        s.Close();
    }
}

【讨论】:

  • finish() 和 close() 的工作方式,而不是 Dispose 模式。 :(
【解决方案3】:

C# MVP Peter Bromberg 的这篇文章可能会解决您的问题:Zip / Unzip folders and files with C#。它有完整的代码和一个示例项目。

【讨论】:

    【解决方案4】:

    我刚刚偶然发现的替代(更方便)解决方案:

    使用SevenZipSharp 项目

    var compressor = new SevenZipCompressor();
    compressor.ArchiveFormat = OutArchiveFormat.SevenZip;
    compressor.CompressionLevel = CompressionLevel.High;
    compressor.CompressionMode = CompressionMode.Create;
    compressor.PreserveDirectoryRoot = false;
    compressor.FastCompression = true;
    compressor.CompressDirectory(dir.FullName, zipFile.FullName);
    

    【讨论】:

      猜你喜欢
      • 2017-08-16
      • 1970-01-01
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      • 1970-01-01
      • 2015-03-29
      • 1970-01-01
      • 2019-05-07
      相关资源
      最近更新 更多