1

I currently got this script, which compresses byte arrays. But I need it rewritten, so it can compress triple byte arrays [,,]

Thanks!

public static byte[] Compress(byte[] buffer)
{
MemoryStream ms = new MemoryStream();
GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true);
zip.Write(buffer, 0, buffer.Length);
zip.Close();
ms.Position = 0;

MemoryStream outStream = new MemoryStream();

byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);

byte[] gzBuffer = new byte[compressed.Length + 4];
Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
return gzBuffer;
}

public static byte[] Decompress(byte[] gzBuffer)
{
MemoryStream ms = new MemoryStream();
int msgLength = BitConverter.ToInt32(gzBuffer, 0);
ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

byte[] buffer = new byte[msgLength];

ms.Position = 0;
GZipStream zip = new GZipStream(ms, CompressionMode.Decompress);
zip.Read(buffer, 0, buffer.Length);

return buffer;
}
3
  • You should ask more of question than request somebody to rewrite this for you. What have you tried? Commented May 10, 2010 at 14:51
  • I'm not very keen at c#, so I really have no idea where to start :) Commented May 10, 2010 at 14:53
  • 6
    I dont understand why so much people downvote this question!? It isnt 'unclear or not useful' (thats what a downvote actually means). If you are angry about the OP just asking us to write code for him: just dont answer and forget the question. I took it as a personal challenge to write it because its actually a very interesting exercise. And if it helps the OP, fine for him, too. That is the spirit of SO, isnt it? Commented May 10, 2010 at 23:16

1 Answer 1

6

Update: I rewrote the code, it is running much faster now and the code is cleaner. Just tested it with some random data (see end of this post).

The Compression method:

public static byte[] Compress(byte[, ,] uncompressed)
{
    if (uncompressed == null)
        throw new ArgumentNullException("uncompressed", 
                                        "The given array is null!");
    if (uncompressed.LongLength > (long)int.MaxValue)
        throw new ArgumentException("The given array is to large!");

    using (MemoryStream ms = new MemoryStream())
    using (GZipStream gzs = new GZipStream(ms, CompressionMode.Compress))
    {
        // Save sizes of the dimensions
        for (int dim = 0; dim < 3; dim++)
            gzs.Write(BitConverter.GetBytes(
                      uncompressed.GetLength(dim)), 0, sizeof(int));

        // Convert byte[,,] to byte[] by just blockcopying it
        // I know, some pointer-magic/unmanaged cast wouldnt 
        // have to copy it, but its cleaner this way...
        byte[] data = new byte[uncompressed.Length];
        Buffer.BlockCopy(uncompressed, 0, data, 0, uncompressed.Length);

        // Write the data to the stream to compress it
        gzs.Write(data, 0, data.Length);
        gzs.Close();

        // Get the compressed byte array back
        return ms.ToArray();
    }
}

The Decompression method:

public static byte[, ,] Decompress(byte[] compressed)
{
    if (compressed == null)
        throw new ArgumentNullException("compressed", 
                                        "Data to decompress cant be null!");

    using (MemoryStream ms = new MemoryStream(compressed))
    using (GZipStream gzs = new GZipStream(ms, CompressionMode.Decompress))
    {
        // Read the header and restore sizes of dimensions
        byte[] dimheader = new byte[sizeof(int) * 3];
        gzs.Read(dimheader, 0, dimheader.Length);
        int[] dims = new int[3];
        for (int j = 0; j < 3; j++)
            dims[j] = BitConverter.ToInt32(dimheader, sizeof(int) * j);

        // Read the data into a buffer
        byte[] data = new byte[dims[0] * dims[1] * dims[2]];
        gzs.Read(data, 0, data.Length);

        // Copy the buffer to the three-dimensional array
        byte[, ,] uncompressed = new byte[dims[0], dims[1], dims[2]];
        Buffer.BlockCopy(data, 0, uncompressed, 0, data.Length);

        return uncompressed;
    }
}

The test code:

Random rnd = new Random();

// Create a new randomly big array, fill it with random data
byte[, ,] uncomp = new byte[rnd.Next(70, 100), 
                       rnd.Next(70, 100), rnd.Next(70, 100)];
for (int x = 0; x < uncomp.GetLength(0); x++)
    for (int y = 0; y < uncomp.GetLength(1); y++)
        for (int z = 0; z < uncomp.GetLength(2); z++)
            uncomp[x, y, z] = (byte)rnd.Next(30, 35);

// Compress and Uncompress again
Stopwatch compTime = new Stopwatch(), uncompTime = new Stopwatch();
compTime.Start();
byte[] comp = Compress(uncomp);
compTime.Stop();
uncompTime.Start();
byte[, ,] uncompagain = Decompress(comp);
uncompTime.Stop();

// Assert all dimension lengths and contents are equal
for (int j = 0; j < 3; j++)
    Debug.Assert(uncomp.GetLength(j) == uncompagain.GetLength(j));

for (int x = 0; x < uncomp.GetLength(0); x++)
    for (int y = 0; y < uncomp.GetLength(1); y++)
        for (int z = 0; z < uncomp.GetLength(2); z++)
            Debug.Assert(uncomp[x, y, z] == uncompagain[x, y, z]);

Console.WriteLine(string.Format("Compression: {0}ms, " +
    "Decompression: {1}ms, Ratio: {2}% ({3}/{4} bytes)",
    compTime.ElapsedMilliseconds, uncompTime.ElapsedMilliseconds,
    (int)((double)comp.LongLength / (double)uncomp.LongLength * 100),
    comp.LongLength, uncomp.LongLength));

Output, for example:

Compression: 77ms, Decompression: 23ms, Ratio: 41% (191882/461538 bytes)
Sign up to request clarification or add additional context in comments.

2 Comments

Your creation of ArgumentNullExceptions is a little off. If you look at the constructor you are using, the parameter is the name of the parameter that is null. If you want to pass a message, you should pass it as the second parameter in the two parameter overload. Oddly, this is not true for the base ArgumentException class which does use message as the single or first of two parameters.
@Gideon: thanks for that, just corrected it. Must have confused it with the overloads of ArgumentException where the message is the first and only parameter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.