Input and Output Stream Pipe in Java

后端 未结 7 1737
闹比i
闹比i 2020-12-17 21:18

Does anyone have any good suggestions for creating a Pipe object in Java which is both an InputStream and and OutputStream since Java does not have multiple inherit

7条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-17 21:52

    I had to implement a filter for slow connections to Servlets so basically I wrapped the servlet output stream into a QueueOutputStream which will add every byte (in small buffers), into a queue, and then output those small buffers to a 2nd output stream, so in a way this acts as input/output stream, IMHO this is better than JDK pipes which won't scale that well, basically there is too much context switching in the standard JDK implementation (per read/write), a blocking queue is just perfect for a single producer/consumer scenario:

    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.concurrent.*;
    
    public class QueueOutputStream extends OutputStream
    {
      private static final int DEFAULT_BUFFER_SIZE=1024;
      private static final byte[] END_SIGNAL=new byte[]{};
    
      private final BlockingQueue queue=new LinkedBlockingDeque<>();
      private final byte[] buffer;
    
      private boolean closed=false;
      private int count=0;
    
      public QueueOutputStream()
      {
        this(DEFAULT_BUFFER_SIZE);
      }
    
      public QueueOutputStream(final int bufferSize)
      {
        if(bufferSize<=0){
          throw new IllegalArgumentException("Buffer size <= 0");
        }
        this.buffer=new byte[bufferSize];
      }
    
      private synchronized void flushBuffer()
      {
        if(count>0){
          final byte[] copy=new byte[count];
          System.arraycopy(buffer,0,copy,0,count);
          queue.offer(copy);
          count=0;
        }
      }
    
      @Override
      public synchronized void write(final int b) throws IOException
      {
        if(closed){
          throw new IllegalStateException("Stream is closed");
        }
        if(count>=buffer.length){
          flushBuffer();
        }
        buffer[count++]=(byte)b;
      }
    
      @Override
      public synchronized void write(final byte[] b, final int off, final int len) throws IOException
      {
        super.write(b,off,len);
      }
    
      @Override
      public synchronized void close() throws IOException
      {
        flushBuffer();
        queue.offer(END_SIGNAL);
        closed=true;
      }
    
      public Future asyncSendToOutputStream(final ExecutorService executor, final OutputStream outputStream)
      {
        return executor.submit(
                new Callable()
                {
                  @Override
                  public Void call() throws Exception
                  {
                    try{
                      byte[] buffer=queue.take();
                      while(buffer!=END_SIGNAL){
                        outputStream.write(buffer);
                        buffer=queue.take();
                      }
                      outputStream.flush();
                    } catch(Exception e){
                      close();
                      throw e;
                    } finally{
                      outputStream.close();
                    }
                    return null;
                  }
                }
        );
      }
    

提交回复
热议问题