【问题标题】:DotNetZip - Calculate final zip size before calling Save(stream) in C#DotNetZip - 在 C# 中调用 Save(stream) 之前计算最终的 zip 大小
【发布时间】:2012-05-30 11:44:13
【问题描述】:

使用 DotNetZip 时,是否可以在调用 Save(stream) 之前获得最终的 zip 文件大小?我有一个应用程序(窗口服务),其中包流大小超过 100MB,然后将保存包并将即将到来的文件添加到新包中。

我收到了same question for web application 但不明白答案。在保存到 I/O 系统之前,有什么方法可以在 DotnetZip 中找到 zip 流的大小?

【问题讨论】:

  • 请解释真正的问题:为什么要事先知道尺寸?因为您无法准确预测最终尺寸。

标签: c# dotnetzip


【解决方案1】:

我得到了解决方案。这是代码。现在我将创建一个小于 100MB 的包。

using System;
using System.Collections;
using System.IO;
using Ionic.Zip;
using Ionic.Zlib;

namespace ZipFileSize1
{
    /// <summary>
    /// This source code is generate the specified size Packages from the directory.
    /// </summary>
    class Program
    {
        /// <summary>
        /// The size of Package(100MB).
        /// </summary>
        public static long m_packageSize = 1024 * 1024 * 100;

        /// <summary>
        ///  Main method of program class.
        /// </summary>
        /// <param name="args">Command line argument</param>
        static void Main(string[] args)
        {
            Console.WriteLine("Enter Directory Full Name for Compression : ");
            var dir = Console.ReadLine();
            Console.WriteLine("Zip File saved Location Directory Name : ");
            var savedir = Console.ReadLine();

            //generate the random zip files.

            var zipFile = Path.Combine(savedir, DateTime.Now.Ticks + ".zip");
            ZipFiles(dir, savedir);

            Console.ReadLine();
        }

        /// <summary>
        /// This method generate the package as per the <c>PackageSize</c> declare.
        /// Currently <c>PackageSize</c> is 100MB.
        /// </summary>
        /// <param name="inputFolderPath">Input folder Path.</param>
        /// <param name="outputFolderandFile">Output folder Path.</param>
        public static void ZipFiles(string inputFolderPath, string outputFolderandFile)
        {
            ArrayList ar = GenerateFileList(inputFolderPath); // generate file list
            int trimLength = (Directory.GetParent(inputFolderPath)).ToString().Length;
            // find number of chars to remove   // from original file path
            trimLength += 1; //remove '\'

            // Output file stream of package.
            FileStream ostream;
            byte[] obuffer;

            // Output Zip file name.
            string outPath = Path.Combine(outputFolderandFile, DateTime.Now.Ticks + ".zip");

            ZipOutputStream oZipStream = new ZipOutputStream(File.Create(outPath), true); // create zip stream

            // Compression level of zip file.
            oZipStream.CompressionLevel = CompressionLevel.Default;

            // Initialize the zip entry object.
            ZipEntry oZipEntry = new ZipEntry();

            // numbers of files in file list.
            var counter = ar.Count;
            try
            {
                using (ZipFile zip = new ZipFile())
                {
                    Array.Sort(ar.ToArray());  // Sort the file list array.
                    foreach (string Fil in ar.ToArray()) // for each file, generate a zip entry
                    {
                        if (!Fil.EndsWith(@"/")) // if a file ends with '/' its a directory
                        {

                            if (!zip.ContainsEntry(Path.GetFullPath(Fil.ToString())))
                            {
                                oZipEntry = zip.AddEntry(Path.GetFullPath(Fil.ToString()), Fil.Remove(0, trimLength));
                                counter--;
                                try
                                {
                                    if (counter > 0)
                                    {
                                        if (oZipStream.Position < m_packageSize)
                                        {
                                            oZipStream.PutNextEntry(oZipEntry.FileName);
                                            ostream = File.OpenRead(Fil);
                                            obuffer = new byte[ostream.Length];
                                            ostream.Read(obuffer, 0, obuffer.Length);
                                            oZipStream.Write(obuffer, 0, obuffer.Length);
                                        }

                                        if (oZipStream.Position > m_packageSize)
                                        {
                                            zip.RemoveEntry(oZipEntry);
                                            oZipStream.Flush();
                                            oZipStream.Close(); // close the zip stream.
                                            outPath = Path.Combine(outputFolderandFile, DateTime.Now.Ticks + ".zip"); // create new output zip file when package size.
                                            oZipStream = new ZipOutputStream(File.Create(outPath), true); // create zip stream                                                
                                        }
                                    }
                                    else
                                    {
                                        Console.WriteLine("No more file existed in directory");
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine(ex.Message);
                                    zip.RemoveEntry(oZipEntry.FileName);
                                }

                            }
                            else
                            {
                                Console.WriteLine("File Existed {0} in Zip {1}", Path.GetFullPath(Fil.ToString()), outPath);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

            }
            finally
            {
                oZipStream.Flush();
                oZipStream.Close();// close stream
                Console.WriteLine("Remain Files{0}", counter);
            }
        }

        /// <summary>
        /// This method return the list of files from the directory
        /// Also read the child directory also, but not add the 0 length file.
        /// </summary>
        /// <param name="Dir">Name of directory.</param>
        /// <returns>return the list of all files including into subdirectory files </returns>
        private static ArrayList GenerateFileList(string Dir)
        {
            ArrayList fils = new ArrayList();

            foreach (string file in Directory.GetFiles(Dir, "*.*", SearchOption.AllDirectories)) // add each file in directory
            {
                if (File.ReadAllBytes(file).Length > 0)
                    fils.Add(file);
            }

            return fils; // return file list
        }      
    }
}

【讨论】:

  • DotNetZip 的创建者“Cheeso”在这里回答了类似的问题:stackoverflow.com/questions/7959211/… 基本上,如果您创建完整(太大)的 zip 文件,那么您可以非常有效地保存由完整 zip 中的所需条目,因此您永远不会不必要地压缩/解压缩。
【解决方案2】:

不明白答案

答案很清楚,但需要对压缩有一些基本的了解。举个例子,看看LZW

归结为:压缩引擎在压缩所有源数据之前并不知道压缩数据的最终大小。而且您不希望这样做两次。

正如 dotnetzip 的documentation 中所述,压缩仅在调用ZipFile.Save() 时开始。

【讨论】:

  • 我想要 100MB 大小的包。当包流大小达到 100MB 时,我的包将保存并创建新包。
  • @sarooptrivedi 然后看看ZipFile.MaxOutputSegmentSize ...虽然保存到流时这不起作用。
  • :ZipFile.MaxOutputSegmentSize 用于分割 Zip 文件。我不想分开。当 Zip 流大小为 100MB 时,我读取了目录并将条目添加到 Zip 流中。保存 zip 并创建新的 zip。
  • @sarooptrivedi 正如我所说:这是不可能的。最多,你可以猜测平均压缩率,只添加文件,直到你猜到结果大小约为 100MB,然后保存 zip 并添加其余文件,直到你添加了大约 100MB 的输入数据,无穷无尽.您还没有说为什么您希望文件只有 100MB。 120MB 有问题吗? 200?演出?
  • 在我的网络代码开发中传递的数据包大小只有100MB。所以我需要限制。
猜你喜欢
  • 2011-07-21
  • 2018-10-17
  • 1970-01-01
  • 2013-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多