ZipInputStream

4 posts, 0 answers
  1. Jhonathan
    Jhonathan avatar
    2 posts
    Member since:
    Jul 2011

    Posted 26 Jul 2011 Link to this post

    Hi,

    I am trying to replace my current zip library with Telerik's one.

    My goal is to improve the transfer of huge objects between SL and WCF.
    I can sucessfully zip my serialized object as in (note that I am using IsolatedStorage instead of memory stream as the objects some times are so big that using memory stream would throw an Out of Memory Exception):
    public static byte[] SerializeAndCompress(T obj)
    {
        var filename = DateTime.Now.ToString("ddMMYYYYhhmmss") + ".xml";
      
        var appStore = IsolatedStorageFile.GetUserStoreForApplication();
      
        if (appStore.Quota < TamanhoStorage) appStore.IncreaseQuotaTo(TamanhoStorage);
      
        byte[] bobj;
      
        using (var fileStream = appStore.OpenFile(filename, FileMode.Create))
        {
            var serializer = new DataContractSerializer(typeof(T));
            serializer.WriteObject(fileStream, obj);
      
            fileStream.Position = 0;
      
            bobj = new byte[fileStream.Length];
            fileStream.Read(bobj, 0, (int)fileStream.Length);
        }
      
        using (var fileStream = appStore.OpenFile(filename, FileMode.Create))
        {
            using (var zip = new ZipOutputStream(fileStream))
            {
                zip.Write(bobj, 0, bobj.Length);
            }
        }
      
        byte[] cobj = null;
      
        using (var fileStream = appStore.OpenFile(filename, FileMode.Open))
        {
            cobj = new byte[fileStream.Length];
            fileStream.Read(cobj, 0, cobj.Length);
        }
      
        appStore.DeleteFile(filename);
      
        return cobj;
    }

    This will compress my object as intended. My problem is reverting this process.
    The only way I was able to achieve this was using a stream reader's ReadToEnd Method, but that won't work, as it will return a string, and I need a byte array (I know I can convert the string back to a byte array, but I'd like to make it in a better way, as in filestream.Read). Code sample:

    using (var fileStream = appStore.OpenFile(filename, FileMode.Open))
        {
            using (var zip = new ZipInputStream(fileStream))
            {
                using (var sr = new StreamReader(zip))
                {
                    var str = sr.ReadToEnd();
                }
            }
        }


    After I call the sr.ReadToEnd method I can see the zip properties filled correctly with the compressed and uncompressed size.
    What I need is the byte array of the decompressed object. Is there a way to achieve this? 

    I tryed the following approach but it didn't work, as I can't foresee the size of the uncompressed object and the decompressed byte array won't be correct:

    var bobj = new byte[5000000];
     
    using (var fileStream = appStore.OpenFile(filename, FileMode.Open))
    {
        using (var zip = new ZipInputStream(fileStream))
        {
            zip.Read(bobj, 0, (int)fileStream.Length);
     
        }
    }

    That will not read the decompressed object correctly, and will waste memory if the object is smaller than the byte array "bobj".

    Thanks in advance.

    Regards

    Take Care

    Jhon
  2. Viktor Tsvetkov
    Admin
    Viktor Tsvetkov avatar
    382 posts

    Posted 27 Jul 2011 Link to this post

    Hello Jhonathan,

    You can have a property in which you will store the length of the file stream before it is compressed via the ZipOutputStream and then you will simply pass it as a size of the byte array. If you have further questions feel free to ask.

    All the best,
    Viktor Tsvetkov
    the Telerik team

    Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

  3. Jhonathan
    Jhonathan avatar
    2 posts
    Member since:
    Jul 2011

    Posted 27 Jul 2011 Link to this post

    Thanks for your response, but unfortunately it did not help me at all, as I will compress in one environment and decompress in another environment, in this case I'd have to send the uncompressed size, and in many cases that won't be possible.

    But, I've found a way to decompress my objects correctly, as follows:

    public static T DecompressAndDeserialize(byte[] cobj)
            {
                var filename = DateTime.Now.ToString("ddMMYYYYhhmmss") + ".xml";
     
                var appStore = IsolatedStorageFile.GetUserStoreForApplication();
     
                using (var fileStream = appStore.OpenFile(filename, FileMode.Create))
                {
                    fileStream.Write(cobj, 0, cobj.Length);
                }
     
                var bobjt = new List<byte>();
                var bufferSize = 1000000;
                byte[] bufObj = null;
     
                using (var fileStream = appStore.OpenFile(filename, FileMode.Open))
                {
                    using (var zip = new ZipInputStream(fileStream))
                    {
                        while (zip.CompressedSize < cobj.Length)
                        {
                            bufObj = new byte[bufferSize];
                            zip.Read(bufObj, 0, bufferSize);
     
                            bobjt.AddRange(bufObj);
                        }
                    }
                }
     
                var index = 0;
     
    //Finding the index of the last valid character starting backwards
                for (var i = bobjt.Count - 1; true; i--)
                {
                    if (bobjt[i] == 0x00) continue;
                     
                    index = i + 1;
                    break;
                }
     
                var bobj = new byte[index];
                Array.Copy(bobjt.ToArray(), bobj, index);
     
                T obj;
     
                using (var fileStream = appStore.OpenFile(filename, FileMode.Create))
                {
                    fileStream.Write(bobj, 0, bobj.Length);
     
                    fileStream.Position = 0;
     
                    var serializer = new DataContractSerializer(typeof(T));
                    obj = (T)serializer.ReadObject(fileStream);
                }
     
                appStore.DeleteFile(filename);
                return obj;
            }

    This will correctly decompresse the object.

    But I've found another issue in the code, that I am not sure if it is related with the ZipLibrary itself or due to the approach I'm using. Consider the following code:

    using (var fileStream = appStore.OpenFile(filename, FileMode.Create))
                {
                    using (var zip = new ZipOutputStream(fileStream))
                    {
                        zip.Write(bobj, 0, bobj.Length);
                    }
                }

    I succefully zipped many different objects  using this approach, zipping objects of 5MB into 365KB arrays. But when I try to compres objects of bigger size, I get an error: "IndexOutOfRangeException" - Index was outside the bounds of the array. The object I am trying to compress is 75MB large. The error is thrown in the zip.write method.

    Stack:
       em Telerik.Windows.Zip.Tree.Code(Int32 dist)
       em Telerik.Windows.Zip.DeflateManager.CompressBlock(Int16[] ltree, Int16[] dtree)
       em Telerik.Windows.Zip.DeflateManager.FlushBlock(Int32 buf, Int32 stored_len, Boolean eof)
       em Telerik.Windows.Zip.DeflateManager.FlushBlockOnly(Boolean eof)
       em Telerik.Windows.Zip.DeflateManager.ProcessSlowDeflate(Int32 flush, Int32& num)
       em Telerik.Windows.Zip.DeflateManager.SlowDeflate(Int32 flush)
       em Telerik.Windows.Zip.DeflateManager.Deflate(ZipBaseStream strm, Int32 flush)
       em Telerik.Windows.Zip.ZipBaseStream.Deflate(Int32 flush)
       em Telerik.Windows.Zip.ZipOutputStream.WriteInternal(Byte[] buf, Int32 offset, Int32 count)
       em Telerik.Windows.Zip.ZipOutputStream.Write(Byte[] buffer, Int32 offset, Int32 count)
       em CCM7.Web.Silverlight.Commom.WFM.Utils.SerializadorDCS`1.SerializarEComprimir(T obj)
       em CCM7.Web.Silverlight.Planejamento.WFM.Paginas.PrevisaoIntraAno.BtnAtualizarClick(Object sender, RoutedEventArgs e)
       em System.Windows.Controls.Primitives.ButtonBase.OnClick()
       em System.Windows.Controls.Button.OnClick()
       em Telerik.Windows.Controls.RadButton.OnClick()
       em System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
       em System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
       em MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)

    Any ideas how to correct this error? is there another approach to zip the stream?

    Thanks in advance.

    Regards

    Take Care

    Jhon
  4. Viktor Tsvetkov
    Admin
    Viktor Tsvetkov avatar
    382 posts

    Posted 27 Jul 2011 Link to this post

    Hello Jhonathan,

    Actually in your scenario it is better and easier if you take advantage of the ZipPackage class, so could you please send me a sample project reproducing your issue, so I will be able to rewrite it using the ZipPackage?

    Greetings,
    Viktor Tsvetkov
    the Telerik team

    Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

Back to Top