DeflateStream unable to write binary streams?
Andreas Raab
andreas.raab at gmx.de
Wed Sep 26 06:33:26 UTC 2007
Matthew Fulmer wrote:
> I was playing with GZipWriteStream and ZLibWriteStream, trying
> to write compressed binary data in the middle of a chunk file,
> like so:
>
> writeDelta: aDelta
> stream nextPutAll: '!DSBinStReader new!'.
> (DataStream on: (GZipWriteStream on: stream)) nextPut: aDelta
>
> This didn't work at all. First, GZipWriteStream wasn't even
> writing to the stream, but to it's own internal collection.
> DeflateStreams seem to try to seize control of the entire
> underlying stream or collection.
Well, let's be careful with the claims here. A couple of examples:
1) Simple compression to an existing stream:
(GZipWriteStream on: (FileStream newFileNamed: 'test.gz'))
nextPutAll: 'Hello World';
close.
2) Embedding compressed data:
stream := String new writeStream.
stream nextPutAll: 'Binary data: '.
(GZipWriteStream on: stream) nextPutAll: 'Hello World'; finish.
stream nextPutAll: 'More data follows'.
stream contents.
3) Embedding compressed binary data in the midst of text:
stream := RWBinaryOrTextStream on: String new.
stream nextPutAll: 'Binary data: '.
stream binary.
(GZipWriteStream on: stream) nextPut: 123; nextPut: 234; finish.
stream ascii.
stream nextPutAll: 'More data follows' asByteArray.
stream contents.
All of the above examples work fine.
> Second, it wouldn't accept the binary data that DataStream was
> feeding it. It seems to only accept character data, as sending
> the message #binary to a DeflateStream does nothing.
DeflateStreams accept binary data if and only if the target stream is
binary. They do not allow switching between binary and non-binary in the
middle of things.
> So, should DeflateStreams be general purpose streams, or is
> there a good reason they are text-only and not embeddable?
Besides it being not true (as the third example above illustrates) it
wouldn't be a problem if it were. You could trivially solve the problem
by using:
writeDelta: aDelta
stream nextPutAll: '!DSBinStReader new!'.
stream nextPutAll: (DataStream streamedRepresentationOf: aDelta)
asString zipped.
which is not significantly more complex than your solution and actually
works - yours doesn't because you either need to #close or #finish the
compressor to write the last block (remember LZ is block based). Note
that #flush is *not* enough here since the LZ family of compressors
marks the last block specifically (#flush will write a block but not
mark it as the last block and upset the decompressor on reading it).
Cheers,
- Andreas
More information about the Squeak-dev
mailing list
|