Iterable gzip deflate/inflate in Java

前端 未结 3 1325
时光说笑
时光说笑 2020-12-21 05:07

Is there a library for gzip-deflating in terms of ByteBuffers hidden in the Internet? Something which allows us to push raw data then pull deflated data? We have searched fo

3条回答
  •  無奈伤痛
    2020-12-21 05:33

    Processing ByteBuffers is not hard. See my sample code below. You need to know how the buffers are created. The options are:

    1. Each buffer is compressed independently. This is so simple to handle I assume this is not the case. You would just transform the buffer into a byte array and wrap it in an ByteArrayInputStream within a GZIPInputStream.
    2. Each buffer was ended with a SYNC_FLUSH by the writer, and thus comprises an entire block of data within a stream. All the data written by the writer to the buffer can be read immediately by the reader.
    3. Each buffer is just part of a GZIP stream. There is no guarantee the reader can read anything from the buffer.

    Data generated by GZIP must be processed in order. The ByteBuffers will have to be processed in the same order they are generated.

    Sample code:

    package stack;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.nio.ByteBuffer;
    import java.nio.channels.Channels;
    import java.nio.channels.Pipe;
    import java.nio.channels.SelectableChannel;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.zip.GZIPInputStream;
    
    public class BufferDeflate {
    
        static AtomicInteger idSrc = new AtomicInteger(1);
    
        /** Queue for transferring buffers */
        final BlockingQueue buffers = new LinkedBlockingQueue();
    
        /** The entry point for deflated buffers */
        final Pipe.SinkChannel bufSink;
    
        /** The source for the inflater */
        final Pipe.SourceChannel infSource;
    
        /** The destination for the inflater */
        final Pipe.SinkChannel infSink;
    
        /** The source for the outside world */
        public final SelectableChannel source;
    
    
    
        class Relayer extends Thread {
            public Relayer(int id) {
                super("BufferRelayer" + id);
            }
    
    
            public void run() {
                try {
                    while( true ) {
                        ByteBuffer buf = buffers.take();
                        if( buf != null ) {
                            bufSink.write(buf);
                        } else {
                            bufSink.close();
                            break;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
    
    
        class Inflater extends Thread {
            public Inflater(int id) {
                super("BufferInflater" + id);
            }
    
    
            public void run() {
                try {
                    InputStream in = Channels.newInputStream(infSource);
                    GZIPInputStream gzip = new GZIPInputStream(in);
                    OutputStream out = Channels.newOutputStream(infSink);
    
                    int ch;
                    while( (ch = gzip.read()) != -1 ) {
                        out.write(ch);
                    }
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
    
        /**
         * New buffer inflater
         */
        public BufferDeflate() throws IOException {
            Pipe pipe = Pipe.open();
            bufSink = pipe.sink();
            infSource = pipe.source();
    
            pipe = Pipe.open();
            infSink = pipe.sink();
            source = pipe.source().configureBlocking(false);
    
            int id = idSrc.incrementAndGet();
    
            Thread thread = new Relayer(id);
            thread.setDaemon(true);
            thread.start();
    
            thread = new Inflater(id);
            thread.setDaemon(true);
            thread.start();
        }
    
    
        /**
         * Add the buffer to the stream. A null buffer closes the stream
         * 
         * @param buf
         *            the buffer to add
         * @throws IOException
         */
        public void add(ByteBuffer buf) throws IOException {
            buffers.offer(buf);
        }
    }
    

    Simply pass the buffers to the add method and read from the public source channel. The amount of data that can be read from GZIP after processing a given number of bytes is impossible to predict. I have therefore made the source channel non-blocking so you can safely read from it in the same thread that you add the byte buffers.

提交回复
热议问题