Java PipedInputStream available()方法返回值

时间:2011-09-23 21:21:03

标签: java inputstream pipe

我正在尝试编写一段解锁代码,以便从PipedInputStream中读取。它基本上检查在调用阻塞读取API之前是否有任何要读取的内容:

int n = 0;
if ((n = pipedInputStream_.available()) > 0) {
     pipedInputStream_.read(...)
}

通过java API doc读取我无法确定该检查应该是什么,因为可能的值为零(表示没有数据,或关闭/中断流)或大于零。那么调用者怎么知道是否有任何东西要读?

  

“返回可以不阻塞地从此输入流中读取的字节数,如果通过调用其close()方法关闭此输入流,或者管道未连接或断开,则返回0。” p>

查看来源,似乎唯一的值为零或大于零。

public synchronized int available() throws IOException {
    if(in < 0)
        return 0;
    else if(in == out)
        return buffer.length;
    else if (in > out)
        return in - out;
    else
        return in + buffer.length - out;
}

2 个答案:

答案 0 :(得分:2)

如果available()返回零,则目前没有可供读取的字节。根据您引用的文档,可能有以下原因:

  • 管道已关闭。
  • 管子坏了。
  • 所有先前可用的输入(如果有)已被消耗。

来自available() 的归零值可能暗示发生了错误,暗示您将来永远无法通过管道读取更多数据,但您可以在这里肯定地说,因为零可能表示上面的第三个条件,InputStream#read()上的阻塞可能最终产生更多数据,相应的OutputStream方将通过管道。

我没有看到可以使用PipedInputStream轮询available(),直到有更多数据可用,因为您永远无法区分上面的终端案例(第一个和第二个) )从读者比作家更饥饿。像这么多的流接口一样,你也必须尝试使用并准备好失败。那是陷阱; InputStream#read()将阻止,但是直到您尝试阻止尝试读取才能识别出不再有输入。

将您的消费操作建立在available()上是不可行的。如果它返回一个正数,那么要读取,但当然即使现在可用的东西也可能不足以满足您的消费者。如果您提交线程以阻塞方式使用InputStream并使用available()跳过轮询,则会发现您的应用程序更易于管理。让InputStream#read()成为你唯一的神谕。

答案 1 :(得分:0)

我需要一个过滤器来拦截慢速连接,我需要尽快关闭数据库连接,所以我最初使用Java管道但是当仔细观察它们的实现时,它全部同步,所以我最终使用一个小缓冲区创建了我自己的QueueInputStream阻塞队列将缓冲区放入队列一旦已满,它是无锁的,除非对于LinkedBlockingQueue使用的锁定条件,借助于小缓冲区它应该是便宜的,这个类只用于单个每个实例的生产者和消费者:

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[]{-1};

  private final BlockingQueue<byte[]> 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 close() throws IOException
  {
    flushBuffer();
    queue.offer(END_SIGNAL);
    closed=true;
  }

  public Future<Void> asyncSendToOutputStream(final ExecutorService executor, final OutputStream outputStream)
  {
    return executor.submit(
            new Callable<Void>()
            {
              @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;
              }
            }
    );
  }

}