0

Requirement: 1) creating split zips file in multiple segments(say size - 1 GB/500 MB), so that they can be downloaded through browser. The total zip volume of all the segments could exceed 10 GB 2) the zip content could be multiple files or a folder containing sub folders and files 3) the content of the file are read from Cloud in the form of stream. The meta information for the files(like folder hierarchy) are locally available

I am using DotNetZip library to achieve the task. The code is as following:

long length = default(long);
            Stream fileReadStream;

            long Space = default(long);
            string tempZipFile = string.Empty;
            FileZipStatus oldStatue = new FileZipStatus();
            byte[] Buffer = new byte[1024 * 1024];

            if (zipFileName != null && !zipFileName.ToUpper().EndsWith(".ZIP")) zipFileName += ".zip";
            string strTempFolder = "";
            using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
            {
                try
                {
                    strTempFolderPath = tempZipOutPutFilePath + "\\";
                    string strTempFolderName = DateTime.Now.Ticks.ToString();
                    strTempFolder = strTempFolderPath + strTempFolderName;
                    if (userFileList.Count > 0)
                    {
                        if (Directory.Exists(strTempFolder))
                        {
                            Directory.Delete(strTempFolder);
                        }
                        Directory.CreateDirectory(strTempFolder);
                    }
                    foreach (UserFile userFile in userFileList)
                    {
                        WebResponse response = null;
                        try
                        {
                            WebRequest request = null;
                            IDictionary<string, object> _dictionary = new Dictionary<string, object>();
                            /// First 
                            FileSystemEnum fileSysEnum = FileSystemBase.GetFileSystemEnumByStorageId(userFile.StorageId);
                            IFileSystemLib ifileSystemLocal = FileSystemFactory.GetSpecificInstance(fileSysEnum);

                            fileReadStream = ifileSystemLocal.GetFile(userFile.FilePath, userFile.GuidName, ref request, ref response, _dictionary);
                            long filesize = default(long);

                            long.TryParse(ifileSystemLocal.GetFileContentLength(userFile.FilePath, userFile.GuidName).ToString(), out filesize);
                            Space = (Space > default(long)) ? (Space + filesize) : filesize;
                            //Now we have to store the data, so that we must access the file

                            int dataToRead;
                            FileStream writeStream = new FileStream(strTempFolder + "\\" + userFile.FileName, FileMode.Create, FileAccess.Write);
                            while ((dataToRead = fileReadStream.Read(Buffer, 0, Buffer.Length)) > 0)
                            {
                                writeStream.Write(Buffer, 0, dataToRead);
                            }
                            writeStream.Close();

                            zip.AddFile(strTempFolder + "\\" + userFile.FileName, userFile.RelativePath);
                            fileReadStream.Close();                            
                        }
                        catch (Exception ex)
                        {
                            LogManager.Trace(ex, "ZIpping Block - ZIPFileName", zipFileName + "File to zip" + userFile.GuidName);
                        }
                        finally
                        {
                            if (response != null) response.Close();
                        }
                    }
                }
                catch (Exception ex)
                {
                    _currentStatus = FileZipStatus.NotAvailable;
                    oldStatue = UpdateZipStatus(ObjectZipID, Space, FileZipStatus.Failed);
                    throw ex;
                }
                finally
                {   
                }
                try
                {
                    zip.Comment = "This zip was created at " + System.DateTime.Now.ToString("G");
                    zip.MaxOutputSegmentSize = 200 * 1024 * 1024;   // 200 mb
                    zip.Save(strTempFolderPath + "\\" + zipFileName);
                    oldStatue = UpdateZipStatus(ObjectZipID, Space, FileZipStatus.Available);
                    length = new FileInfo(strTempFolderPath + "\\" + zipFileName).Length;
                    _currentStatus = FileZipStatus.Available;
                    // deleting temp folder
                    Directory.Delete(strTempFolder, true);
                }
                catch (Exception ex)
                {
                    _currentStatus = FileZipStatus.NotAvailable;
                    oldStatue = UpdateZipStatus(ObjectZipID, Space, FileZipStatus.Failed);
                    length = default(long);
                    throw ex;
                }
            }

There are a limitation of the DotNetZip libray used in the above code. It either needs a) files saved on disk as input. In that case folder hierarchy information could be passed for each file. or 2) if stream is passed as input, folder hierarchy information could NOT be passed for file.

I need to pass in the folder hierarchy information for each file as well as read the input from stream. As the zip content could be huge(could exceed 10 GB), do not want to save the files on temporary storage in web server. Can Anyone help like how to pass folder hierarchy when creating zip file? thanks

Mou
  • 15,673
  • 43
  • 156
  • 275

2 Answers2

0

i got the solution. here is the code

private void button2_Click(object sender, EventArgs e)
        {
            using (SqlConnection sqlConn = new SqlConnection(@"Data Source=BBATRIDIP\SQLSERVER2008R2;Initial Catalog=test;Integrated Security=True"))
            {
                string query = String.Format(@"SELECT [FilePath],[FileName],[FileData] FROM [TestTable]");
                SqlCommand cmd = new SqlCommand(query, sqlConn);
                cmd.Connection.Open();

                System.IO.MemoryStream memStream = null;
                ZipFile zip = new ZipFile();
                zip.MaxOutputSegmentSize = 1024 * 1024; // 1MB each segment size would be
                // the above line would split zip file into multiple files and each file
                //size would be 1MB
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        byte[] data = (byte[])reader["FileData"];
                        memStream = new System.IO.MemoryStream(data);
                        string strFile = reader["FilePath"].ToString() + "\\" + reader["FileName"].ToString();
                        ZipEntry ze = zip.AddEntry(strFile, memStream);
                    }
                }
                zip.Save(@"e:\MyCustomZip.zip");
                memStream.Dispose();
                MessageBox.Show("Job Done");
                // here u can save the zip in memory stream also there is a overload insteaa of saving in HD
            }
        }
Mou
  • 15,673
  • 43
  • 156
  • 275
-1

this approach stores the zip content in memory. Hence, when the zip content is huge, say exceeds 5 GB then then it crashes. Need to write to fileOutputStream mapped to physical file

  • can u discuss how to write to fileOutputStream mapped to physical file with bits of hints and sample code. thanks – Mou Apr 17 '15 at 19:36