1

I'm trying to zip a memory stream into another memory stream so I can upload to a rest API. image is the initial memory stream containing a tif image.

WebRequest request = CreateWebRequest(...);
request.ContentType = "application/zip";
MemoryStream zip = new MemoryStream();
GZipStream zipper = new GZipStream(zip, CompressionMode.Compress);
image.CopyTo(zipper);
zipper.Flush();
request.ContentLength = zip.Length; // zip.Length is returning 0
Stream reqStream = request.GetRequestStream();
zip.CopyTo(reqStream);
request.GetResponse().Close();
zip.Close();

To my understand, anything I write to the GZipStream will be compressed and written to whatever stream was passed into it's constructor. When I copy the image stream into zipper, it appears nothing is actually copied (image is 200+ MB). This is my first experience with GZipStream so it's likely I'm missing something, any advice as to what would be greatly appreciated.

EDIT: Something I should note that was a problem for me, in the above code, image's position was at the very end of the stream... Thus when I called image.CopyTo(zipper); nothing was copied due to the position.

Corey Ogburn
  • 24,072
  • 31
  • 113
  • 188
  • Just a note: You won't get very impressive results if your TIFFs are already compressed (most are, I think). – Cameron Jun 06 '11 at 16:45
  • These are uncompressed GeoTiffs. Also, the REST API I'm uploading these images to require the upload to be a zip. – Corey Ogburn Jun 06 '11 at 16:46

3 Answers3

3

[Edited: to remove incorrect info on GZipStream and it's constructor args, and updated with the real answer :) ]

After you've copied to the zipper, you need to shift the position of the MemoryStream back to zero, as the process of the zipper writing to the memory stream advances it's "cursor" as well as the stream being read:

WebRequest request = CreateWebRequest(...);
request.ContentType = "application/zip";
MemoryStream zip = new MemoryStream();
GZipStream zipper = new GZipStream(zip, CompressionMode.Compress);
image.CopyTo(zipper);
zipper.Flush();
zip.Position = 0; // reset the zip position as this will have advanced when written to.
...

One other thing to note is that the GZipStream is not seekable, so calling .Length will throw an exception.

Rob Levine
  • 40,328
  • 13
  • 85
  • 111
  • +1 for explaining that the GZipStream isn't seekable, but the MSDN examples add data to the GZip stream *after* it's been created (not the underlying stream). The OP hasn't misunderstood – Cameron Jun 06 '11 at 16:53
  • zipper.CopyTo(reqStream) throws an exception. zipper cannot be read from. – Corey Ogburn Jun 06 '11 at 16:55
  • After reading thekip's linked MSDN article several times, and the more I look at your example... The more I think you misunderstand GZipStream. – Corey Ogburn Jun 06 '11 at 17:00
0

I don't know anything about C# and its libraries, but I would try to use Close instead of (or after) Flush first.

(Java's GZipOutputStream has the same problem that it doesn't properly flush, until Java 7.)

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • It appears that Close() indeed is the problem! zipper.Close() was missing for me and I am sure it is missing for the original issue. See this answer: http://stackoverflow.com/questions/6334463/gzipstream-compression-problem-lost-byte – Vasyl Boroviak Sep 09 '13 at 06:46
-1

See this example: http://msdn.microsoft.com/en-us/library/system.io.compression.gzipstream.flush.aspx#Y300

You shouldn't be calling flush on the stream.

thekip
  • 3,660
  • 2
  • 21
  • 41
  • Other than the using statements, I don't see a difference between what the example does and what I'm doing. I do plan to add the using statements when I get this working, until then I don't want them playing havoc with what's in what scope. – Corey Ogburn Jun 06 '11 at 16:51
  • What's wrong with calling `Flush()`? It seems perfectly legitimate – Cameron Jun 06 '11 at 16:51