7

When using DotNetZip, is it possible to get what the final zip file size will be before calling Save(stream)? I have a application(Window Service) where package Stream size is more than 100MB then package will saved and upcoming files add into new package.

I got same question for web application but not understand the answer. Is there any way into DotnetZip to find the size of zip stream before save on I/O system?

Community
  • 1
  • 1
Saroop Trivedi
  • 2,245
  • 6
  • 31
  • 49
  • Please explain the real problem: why do you want to know the size on beforehand? Because you cannot accurately predict the final size. – CodeCaster May 30 '12 at 12:00

2 Answers2

9

I got the solution. Here is code.Now I will create the package which size is less then 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
        }      
    }
}
Saroop Trivedi
  • 2,245
  • 6
  • 31
  • 49
  • 2
    The creator of DotNetZip, "Cheeso," answered a similar question here: http://stackoverflow.com/questions/7959211/dotnetzip-creating-zip-from-subset-of-other-zip Basically, if you create the full (too big) zip file, then you can very efficiently save new zips built from the desired entries in the full zip, so you'll never compress/decompress unnecessarily. – Derek Kurth Mar 09 '15 at 17:16
2

not understand the answer

The answer is quite clear, but requires some fundamental understanding of compression. Take, for example, a look at LZW.

It comes down to this: a compression engine does not know the final size of the compressed data before compressing all the source data. And you'd rather not want to do that twice.

As explained in the documentation of dotnetzip, the compression only starts when calling ZipFile.Save().

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • I want 100MB size package.When Package Stream size reach at 100MB my package will save and create new Package. – Saroop Trivedi May 30 '12 at 12:09
  • @sarooptrivedi then take a look at [`ZipFile.MaxOutputSegmentSize `](http://cheeso.members.winisp.net/DotNetZipHelp/html/b2923f86-bc4a-7d64-381e-d7fbabdb5ed0.htm)... although that doesn't work when saving to a stream. – CodeCaster May 30 '12 at 12:14
  • :ZipFile.MaxOutputSegmentSize use for split Zip file. I don't want to split. I read the directory and add entry into Zip stream when Zip stream size is 100MB. Save the zip and create new zip. – Saroop Trivedi May 30 '12 at 12:25
  • @sarooptrivedi as I said: that's not possible. At most, you could guesstimate the average compression rate, and only add files until you guess the resulting size is about 100MB, then save the zip and add the rest of the files until you've added about 100MB's worth of input data, ad infinitum. You still haven't said **why** you want the files to become only 100MB. Is 120MB a problem? 200? A gig? – CodeCaster May 30 '12 at 12:37
  • In my network code development passing packet size is 100MB only.So I need the limitation. – Saroop Trivedi May 30 '12 at 13:15