file -> zip ->stream ->byte[] ->base64 string

Mar 26, 2010 at 4:32 AM

Who can help me?

Who can give me an example to achieve?

Read file, then use DotNetZip  compress, then convert to byte[,  convert to base64 string at last.

Thanks a lot! Thanks

Coordinator
Mar 26, 2010 at 6:01 PM
Edited Mar 26, 2010 at 6:05 PM

To do what you describe, you can call ZipFile.Save(), specifying a MemoryStream,  then call .ToArray() on the MemoryStream to get the byte array, Then use your base64 encoder on the result to get a string.

But you've explicitly specified that you want a byte array as an intermediate step, and often that's not necessary.  You can use a streaming approach to skip the intermediate steps.  This way, the compression, and base64 encoding, happens in a stream.  In other words, the first bytes are compressed, and then base64-encoded, before the last bytes are compressed and encoded.  There is no moment where you have an array or memory location that contains the entire compressed-but-not-encoded stream, if you see what I mean.  As a result, streaming approaches for data processing (like compression + encoding, as you are doing) can be much more efficient in terms of time and memory.

The concept of IO Streaming can be difficult to understand at first so if you don't quite see what I mean, then I suggest you do some reading on the topic.

Also - are you sure you want a zip file? 

What you're describing - compression of a single file and transmission of that file as a bytestream - might more effectively be done with a DeflateStream or GZipStream.  These are "bare" compression formats, with less overhead than a zip file, and possibly more efficient if you are compressing just one file.  In fact the DeflateStream is used to produce the compressed data which is stored every zip file, and then augmented with the zip directory information, the checksums, file attributes and so on. Because of that extra "metadata", the zip file will always be larger than a DEFLATE'd stream.  

If you employ streaming, and you use a "bare" compression stream, then what you want to do is something like this:

byte[] working= new byte[1024];
int n;
using (Stream input = File.OpenRead(fileToCompress))
{
    using (Stream output = new MemoryStream())
    {
        using (var b64 = new Base64Stream(output, Base64Stream.Mode.Encode))
        {
            using (var compressor = new DeflateStream(b64, CompressionMode.Compress, true))
            {
                while ((n = input.Read(working, 0, working.Length)) != 0)
                {
                    compressor.Write(working, 0, n);
                }
            }
        }
    }
}

Just to walk you through the code - at the top, you open the input and output streams.  The input is a FileStream; the output is a MemoryStream, which just collects the result in memory.  Each of those is opened in a using clause, because they're IDisposable.  Ok, then it gets more interesting.  The next step is to create a Base64Stream (again in a using clause), wrapped around the output stream.  As the app writes to the Base64Stream, the input data will be base64-encoded before being sent to the output, which in this case is a MemoryStream as I said.  Next, the code instantiates a DeflateStream around the Base64Stream.  Anything written into the DeflateStream will first be deflated, before being written out to the Base64Stream. 

All that remains is to read the input, and write to the compressor.  This is done in the inner-most loop in the code above.  The compressor is the first link in chain of three streams, the comibination of which does what you asked for.  The loop runs until no more data can be read from the input.

Pretty simple.

If you really DO want a zipfile, and not just a bare compression stream, then replace the DeflateStream with a ZipOutputStream, and call .PutEntry() on that, once, just before beginning the read/write loop. 

But this supposes that you have access to a Base64Stream, which can do the b64 encoding.  As far as I know, there is no such class included in the .NET Base class library. Puzzling. When I needed to do base64, I wrote a base64 stream class.

 

Coordinator
Mar 26, 2010 at 6:44 PM
Edited Mar 26, 2010 at 7:03 PM

ps: Here's the Base64Stream class I mentioned:

http://cheeso.members.winisp.net/srcview.aspx?file=Base64stream.cs

Licensed under the MS-Public License. 

You can also use System.Convert.ToBase64String(byteArray);  

This makes sense if the data is fairly small.

 
May 11, 2010 at 5:46 PM

Cheeso, the link http://cheeso.members.winisp.net/srcview.aspx?file=Base64stream.cs is broken.

Do u have it anywhere else ? does it work only at .NET 3.5 ?

thanks

Coordinator
May 11, 2010 at 6:40 PM

yes, try: http://cheeso.members.winisp.net/srcview.aspx?dir=streams&file=Base64Stream.cs .

Yes, it requires .NET 3.5.   You could compile it for .NET 2.0, I think.  I haven't tried it though.  You'd have to fix all the C# 3.0 compiler things - like the use of the "var" type, object initializers, and so on.  I don't think it uses any .NET 3.5-only assemblies.