When to zip on the fly

    The task is trivial. You make some reports, files and want to enable the user to download them in his ASP.NET application. Why is it useful to use archiving ?: a) the download volume is reduced b) you can give files in batches in several.
    In .net there is a special class for working with GZip, located in System.IO.Compression , and is called GZipStream , but it does not allow you to store multiple files in one archive, such a specificity. Of course, there are enthusiasts who use it to create full-fledged zip archives (though they, it seems, can only open them using their programs - at least I came across only such ones).
    In .NET 3.0 and later, you can use the ZipPackage class from System.IO.Packaging, which is located in the WindowsBase.DLL assembly (located approximately in C: \ Program Files \ Reference Assemblies \ Microsoft \ Framework \ v3.0 \ WindowsBase.dll), I don’t know why this assembly does not lie in the GAC, here is an example how it's all to use: Creating Zip archives in .NET (without an external library like SharpZipLib) .
    But still, if you use SharpZipLib , how to do archiving in memory? Surely, it can be done through OutputZipStream. But I liked the FileZip class, which has the Add () method into which you can pass the file name, or the finished ZipEntry, as well as the ability to pass an object with a type inherited from IStaticDataSource.

    So, we implement a class that will be used as a Stream (stream) for archiving by the FileZip class:
    ///
    /// Реализация ресурса для зипования
    ///

    class MemoryStreamStaticDataSource : ICSharpCode.SharpZipLib.Zip.IStaticDataSource, IDisposable
    {
      private MemoryStream MemoryStream { get; set; }

      ///
      /// Создаем ресурс с MemoryStream
      ///

      ///
      public MemoryStreamStaticDataSource(byte[] bytes)
      {
        MemoryStream = new MemoryStream(bytes) { Position = 0 };
      }

      #region IStaticDataSource Members

      public Stream GetSource()
      {
        return MemoryStream;
      }

      #endregion

      #region IDisposable Members

      public void Dispose()
      {
        if (MemoryStream != null)
          MemoryStream.Dispose();
      }

      #endregion
    }

    * This source code was highlighted with Source Code Highlighter.

    Let’s have files in the form of a set of bytes (byte []), the idea is that we don’t want to store these files physically, only in RAM. The task - we generate these files ourselves, for example, I wrote this code:
    ///
    /// Пример, получаем данные первого сгенерированного файла
    ///

    ///
    private static byte[] GetFirstFileData()
    {
      return GetFileData(@"Первый файл.");
    }

    ///
    /// Пример, получаем данные второго сгенерированного файла
    ///

    ///
    private static byte[] GetSecondFileData()
    {
      return GetFileData(@"Второй файл.");
    }

    private static byte[] GetFileData(string textdata)
    {
      return Encoding.UTF8.GetBytes(textdata);
    }

    * This source code was highlighted with Source Code Highlighter.

    So, the latter, using the ZipFile class, we add our fake files to the archive and return the pages to the Response (instead of the page content).
    ///
    /// Переопределяем загрузку страницы, и возвращаем zip файл
    ///

    ///
    protected override void OnLoad(EventArgs e)
    {
      base.OnLoad(e);

      Response.Clear();
      //Указывает MIME тип
      Response.ContentType = "application/zip";
      //Указываем, что приаттачен файл с именем file.zip
      Response.AddHeader("Content-Disposition", string.Format("attachment; filename=\"{0}\"", HttpUtility.UrlEncodeUnicode("file.zip")));

      //Получаем данные(файл архива) и записываем в Response
      byte[] bytes = GetZipData();
      Response.OutputStream.Write(bytes, 0, bytes.Length);
    }

    private static byte[] GetZipData()
    {
      //Создаем архив в памяти
      using (MemoryStream ms = new MemoryStream())
      {
        using (ICSharpCode.SharpZipLib.Zip.ZipFile file = new ICSharpCode.SharpZipLib.Zip.ZipFile(ms))
        {
          file.BeginUpdate();

          //Добавляем в архив первый файл
          file.Add(new MemoryStreamStaticDataSource(GetFirstFileData()), "file1.txt");
          //Добавляем в архив второй файл
          file.Add(new MemoryStreamStaticDataSource(GetSecondFileData()), "file2.txt");

          file.CommitUpdate();
        }

        return ms.ToArray();
      }
    }

    * This source code was highlighted with Source Code Highlighter.

    As a result, we get an aspx page that will return a zip archive with two files.
    Download example ...

    Also popular now: