0

I need to compress a file using GZip by batch of specified size (not in a whole). I can successfuly fill the byte[] buffer, but after copying it into the compression stream, it just leaves the output stream empty.

public void Compress(string source, string output)
    {
        FileInfo fi = new FileInfo(source);
        byte[] buffer = new byte[BufferSize];
        int total, current = 0;
        using (FileStream inFile = fi.OpenRead())
        {
            using (FileStream outFile = File.Create(output + ".gz"))
            {
                while ((total = inFile.Read(buffer, 0, buffer.Length)) != 0)
                {
                    using (MemoryStream compressedStream = new MemoryStream())
                    {
                        using (MemoryStream bufferStream = new MemoryStream())
                        {
                            CopyToStream(buffer, bufferStream);
                            using (GZipStream Compress = new GZipStream(compressedStream, CompressionMode.Compress, true))
                            {
                                bufferStream.Position = 0;
                                bufferStream.CopyTo(Compress);
                                current += total;
                            }
                            compressedStream.Position = 0;
                            compressedStream.CopyTo(outFile);
                        }
                    }
                }
            }
        }
    }

    static void CopyToStream(byte[] buffer, Stream output)
    {
        output.Write(buffer, 0, buffer.Length);
    }
Ondrej Sotolar
  • 1,352
  • 1
  • 19
  • 29

2 Answers2

1

You need to rewind compressedStream by setting Position=0 before compressedStream.CopyTo(outFile);.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Note that my answer is for your precise problem, but you may simply be doing wrong by compressing chunk at a time. I think .gz is expected to be single compressed block with one compression dictionary. Your code may be creating file unreadable by normal de-compressors. – Alexei Levenkov Apr 27 '12 at 19:39
  • How would you do it? The reason for the batch processing is progress monitoring. I thought that I would fire an event after each batch is completed. I don't think that I can touch the compression stream itself, so I designed it this way. – Ondrej Sotolar Apr 27 '12 at 20:09
  • See no problem with doing it. Why do you need to commit each chunk to fire event after every x bytes written to the stream? – Alexei Levenkov Apr 27 '12 at 20:25
  • Not sure I understand the question properly, but I'll try to answer. I need to fire an event after each batch is processed because I have it in instructions (not my idea). I think it's puprose is to drive a prorgess bar or something like that. – Ondrej Sotolar Apr 27 '12 at 20:43
  • I have no idea what you need to do, so let's consider it solved. (For event I mean to be fired around bufferStream.CopyTo(Compress) and moving Compress stream outside while loop) – Alexei Levenkov Apr 27 '12 at 20:48
0

You are trying to over complicate things... You do not require additional MemoryStreams or buffers...

Taken from the MSDN... http://msdn.microsoft.com/en-us/library/system.io.compression.gzipstream.aspx

public static void Compress(FileInfo fi)
    {
        // Get the stream of the source file.
        using (FileStream inFile = fi.OpenRead())
        {
            // Prevent compressing hidden and 
            // already compressed files.
            if ((File.GetAttributes(fi.FullName) 
                & FileAttributes.Hidden)
                != FileAttributes.Hidden & fi.Extension != ".gz")
            {
                // Create the compressed file.
                using (FileStream outFile = 
                            File.Create(fi.FullName + ".gz"))
                {
                    using (GZipStream Compress = 
                        new GZipStream(outFile, 
                        CompressionMode.Compress))
                    {
                        // Copy the source file into 
                        // the compression stream.
                    inFile.CopyTo(Compress);

                        Console.WriteLine("Compressed {0} from {1} to {2} bytes.",
                            fi.Name, fi.Length.ToString(), outFile.Length.ToString());
                    }
                }
            }
        }
    }
craig1231
  • 3,769
  • 4
  • 31
  • 34