Read and write gzip files easily.

Stephan Schiffels stephan_schiffels at mac.com
Thu Feb 20 02:35:48 PST 2014


On Wednesday, 19 February 2014 at 15:51:53 UTC, Kamil Slowikowski 
wrote:
> Hi there, I'm new to D and have a lot of learning ahead of me. 
> It would
> be extremely helpful to me if someone with D experience could 
> show me
> some code examples.
>
> I'd like to neatly read and write gzipped files for my work. I 
> have read
> several threads on these forums on the topic of std.zlib or 
> std.zip and I haven't been able to figure it out.
>

Hi Kamil,
I am glad someone has the exact same problem as I had. I actually 
solved this, inspired by the python API you quoted above. I wrote 
these classes:
GzipInputRange, GzipByLine, and GzipOut.
Here is how I can now use them:

_____________________

import gzip;
import std.stdio;

void main() {
auto byLine = new GzipByLine("test.gz");
foreach(line; byLine)
    writeln(line);

auto gzipOutFile = new GzipOut("testout.gz");
gzipOutFile.compress("bla bla bla");
gzipOutFile.finish();
}

That is all quite convenient and I was wondering whether 
something like that would be useful even in Phobos. But it's 
clear that for phobos things would involve a lot more work to 
comply with the requirements. This so far simply served my needs 
and is not as generic as it could be:

Here is the code:

___________gzip.d__________________
import std.zlib;
import std.stdio;
import std.range;
import std.traits;

class GzipInputRange {
   UnCompress uncompressObj;
   File f;
   auto CHUNKSIZE = 0x4000;
   ReturnType!(f.byChunk) chunkRange;
   bool exhausted;
   char[] uncompressedBuffer;
   size_t bufferIndex;

   this(string filename) {
     f = File(filename, "r");
     chunkRange = f.byChunk(CHUNKSIZE);
     uncompressObj = new UnCompress();
     load();
   }

   void load() {
     if(!chunkRange.empty) {
       auto raw = chunkRange.front.dup;
       chunkRange.popFront();
       uncompressedBuffer = 
cast(char[])uncompressObj.uncompress(raw);
       bufferIndex = 0;
     }
     else {
       if(!exhausted) {
         uncompressedBuffer = cast(char[])uncompressObj.flush();
         exhausted = true;
         bufferIndex = 0;
       }
       else
         uncompressedBuffer.length = 0;
     }
   }

   @property char front() {
     return uncompressedBuffer[bufferIndex];
   }

   void popFront() {
     bufferIndex += 1;
     if(bufferIndex >= uncompressedBuffer.length) {
       load();
       bufferIndex = 0;
     }
   }

   @property bool empty() {
     return uncompressedBuffer.length == 0;
   }
}

class GzipByLine {
   GzipInputRange range;
   char[] buf;

   this(string filename) {
     this.range = new GzipInputRange(filename);
     popFront();
   }

   @property bool empty() {
     return buf.length == 0;
   }

   void popFront() {
     buf.length = 0;
     while(!range.empty && range.front != '\n') {
       buf ~= range.front;
       range.popFront();
     }
     range.popFront();
   }

   string front() {
     return buf.idup;
   }
}

class GzipOut {
   Compress compressObj;
   File f;

   this(string filename) {
     f = File(filename, "w");
     compressObj = new Compress(HeaderFormat.gzip);
   }

   void compress(string s) {
     auto compressed = compressObj.compress(s.dup);
     f.rawWrite(compressed);
   }

   void finish() {
     auto compressed = compressObj.flush();
     f.rawWrite(compressed);
   }
}




More information about the Digitalmars-d mailing list