Fandi Susanto Fandi Susanto - 2 months ago 44
C# Question

C# buffered GZipStream compression

I'm writing a

database
backup function, reading from a
System.Diagnostics.Process object
, from
StandardOutput (StreamReader)
Property. I have succeeded in writing to plain file.

//This code successfully wrote text files.
StreamWriter f = new StreamWriter(BackupPath);
while (true) {
//RaiseProgressedEvent(new DBProgressEventArgs(dbsize, progress, "Writing backup file"));

int buffsize = 512;
char[] buff = new char[buffsize];
int count = p.StandardOutput.ReadBlock(buff, 0, buff.Length);
if (count == 0) break;
// If no more data, trim the char array
if (p.StandardOutput.Peek() < 0) buff = (from c in buff where c > 0 select c).ToArray();

f.Write(buff, 0, count);
progress += buffsize;
}
f.Close();


But when i change to
GZipStream
:

//This code yields a broken gzip file.
//*2 lines changed: StreamWriter changed into FileStream.
FileStream fs = File.Create(BackupPath);
GZipStream zipStream = new GZipStream(fs, CompressionMode.Compress, true);

while (true) {
RaiseProgressedEvent(new DBProgressEventArgs(dbsize, progress, "Writing backup file"));

int buffsize = 512;
char[] buff = new char[buffsize];
int count = p.StandardOutput.ReadBlock(buff, 0, buff.Length);
if (count == 0) break;
if (p.StandardOutput.Peek() < 0) buff = (from c in buff where c > 0 select c).ToArray();

//With UTF 8 Encoding, write to gzipstream.
//f.write changed into the following 2 lines:
Encoding enc = Encoding.UTF8;
zipStream.Write(enc.GetBytes(buff), 0, enc.GetByteCount(buff));

progress += buffsize;
}
fs.Close();


The resulting
GZip
file is incomplete/broken. When decompressed with
7zip
and then opened with
notepad++
, almost all the text is good, only some bytes near the ending of the file are lost. I am not sure, but perhaps the error is near:
zipStream.Write(enc.GetBytes(buff), 0, enc.GetByteCount(buff));

Perhaps something to do with the
enc.GetByteCount(buff)
.

The reading is buffered for multithreading, for handling large files. So... why did the last bytes are lost? Where did i do wrong?

Answer

Try something like:

  • Use a constructor of GZipStream, which close the FileStream post Dispose

    using(FileStream fs = File.Create(BackupPath))
    using(GZipStream zipStream = new GZipStream(fs, CompressionMode.Compress, false))
    {
    
     while (true) {
      RaiseProgressedEvent(new DBProgressEventArgs(dbsize, progress, "Writing backup file"));
    
     int buffsize = 512;
     char[] buff = new char[buffsize];
     int count = p.StandardOutput.ReadBlock(buff, 0, buff.Length);
     if (count == 0) break;
     if (p.StandardOutput.Peek() < 0) buff = (from c in buff where c > 0 select c).ToArray();
    
     //With UTF 8 Encoding, write to gzipstream.
     //f.write changed into the following 2 lines:
     Encoding enc = Encoding.UTF8;
     zipStream.Write(enc.GetBytes(buff), 0, enc.GetByteCount(buff));
    
     progress += buffsize;
    }
    }