Search code examples
c#streamreadermemorystream

Unzipping a file from Base64 to string using DotNetZip


When I am trying to unzip a file in code I get the following error.

   at System.IO.StreamReader..ctor(Stream stream, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize, Boolean leaveOpen)
   at System.IO.StreamReader..ctor(Stream stream)
   at Arkle.AzureServiceBusSample.MessageFetcher.ConvertBase64ZippedStringToNormalString(String stringBase64Zipped) in c:\CodeTfsArklePosBenLenovo\Arkle.AzureServiceBusSample\Arkle.AzureServiceBusSample\MessageFetcher.cs:line 171
   at Arkle.AzureServiceBusSample.MessageFetcher.DownloadMessages(String username, String password, String identifier) in c:\CodeTfsArklePosBenLenovo\Arkle.AzureServiceBusSample\Arkle.AzureServiceBusSample\MessageFetcher.cs:line 92
   at Arkle.AzureServiceBusSample.MessageFetcher.ReceiveMessages(String username, String password, String endPoint, String subscriptionName) in c:\CodeTfsArklePosBenLenovo\Arkle.AzureServiceBusSample\Arkle.AzureServiceBusSample\MessageFetcher.cs:line 48

System.ArgumentException: Stream was not readable. at System.IO.StreamReader..ctor(Stream stream, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, |nt32 bufferSize, Boolean |eaveOpen) at System.IO.StreamReader..ctor(Stream stream)

It happens on the line var streamReader1 = new StreamReader(ms); I have checked and just above that I am able to save the file to disk and it is unzipped correctly. However I need to unzip it directly to a memory stream.

I'm using DotNetZip version 1.9.2.

My Code:

    using ionic.zip;

    .............
    public static string UnzipToString(string stringBase64Zipped)
    {
        var bytesZipFile = Convert.FromBase64String(stringBase64Zipped);

        var msZipFile = new MemoryStream(bytesZipFile);
        msZipFile.Position = 0;
        using (var zipFile1 = ZipFile.Read(msZipFile))
        {
            zipFile1.Save(string.Format(@"C:\Temp\{0}.zip", Guid.NewGuid()));  // This works
            var zipEntry1 = zipFile1.Entries.First();

            using (var ms = new MemoryStream())
            {
                ms.Position = 0;
                zipEntry1.Extract(ms);
                var streamReader1 = new StreamReader(ms);
                var result = String.Empty;
                ms.Position = 0;
                result = streamReader1.ReadToEnd();

                return result;
            }
        }
    }

Line and error when it stopz

I have got a new error now when I try and set the memeorystream position to 0 as per the suggestion below.

System.ObjectDisposedException: Cannot access a closed Stream.

   at System.IO.__Error.StreamIsClosed()

   at System.IO.MemoryStream.set_Position(Int64 value)

   at Arkle.AzureServiceBusSample.MessageFetcher.ConvertBase64ZippedStringToNormalString(String stringBase64Zipped) in c:\CodeTfsArklePosBenLenovo\Arkle.AzureServiceBusSample\Arkle.AzureServiceBusSample\MessageFetcher.cs:line 171

   at Arkle.AzureServiceBusSample.MessageFetcher.DownloadMessages(String username, String password, String identifier) in c:\CodeTfsArklePosBenLenovo\Arkle.AzureServiceBusSample\Arkle.AzureServiceBusSample\MessageFetcher.cs:line 92

   at Arkle.AzureServiceBusSample.MessageFetcher.ReceiveMessages(String username, String password, String endPoint, String subscriptionName) in c:\CodeTfsArklePosBenLenovo\Arkle.AzureServiceBusSample\Arkle.AzureServiceBusSample\MessageFetcher.cs:line 48

Solution

  • Not sure what you are going to archieve. Here is my sample code which works

            private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
            {
                var bytes = File.ReadAllBytes(@"e:\scripts_04-10-2014.zip");
                var zipAsBase64 = Convert.ToBase64String(bytes);
    
                foreach (var item in GetUnzippedItemsAsStream(zipAsBase64))
                {
                    using (var fs = new FileStream(Path.Combine(@"e:\", item.Item1), FileMode.CreateNew,
                            FileAccess.ReadWrite))
                    {
                        item.Item2.CopyTo(fs);
                    }
                }
            }
    
            public IEnumerable<Tuple<string, Stream>> GetUnzippedItemsAsStream(string stringBase64Zipped)
            {
                var bytesZipFile = Convert.FromBase64String(stringBase64Zipped);
                using (var ms = new MemoryStream(bytesZipFile))
                {
                    using (var zipFile = ZipFile.Read(ms))
                    {
                        foreach (var zipEntry in zipFile.Entries)
                        {
                            var outputStream = new MemoryStream();
                                zipEntry.Extract(outputStream);
                                yield return new Tuple<string, Stream>(zipEntry.FileName, new MemoryStream(outputStream.ToArray()));
                        }
                    }
                }
            }
    

    Please note the following code

      zipEntry.Extract(outputStream);
      yield return new Tuple<string, Stream>(zipEntry.FileName, new MemoryStream(outputStream.ToArray()));
    

    I was needed to create new MemoryStream with old.ToArray() (which works even with closed MemoryStreams) because there is a known issue in current DotNetZipLib about closing the stream after extracting.