是否可以从具有超时的InputStream读取? [英] Is it possible to read from a InputStream with a timeout?

查看:109
本文介绍了是否可以从具有超时的InputStream读取?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具体来说,问题是写一个这样的方法:

Specifically, the problem is to write a method like this:

int maybeRead(InputStream in, long timeout)

如果数据在'timeout'毫秒内可用,则返回值与in.read()相同,否则为-2。在方法返回之前,任何生成的线程都必须退出。

where the return value is the same as in.read() if data is available within 'timeout' milliseconds, and -2 otherwise. Before the method returns, any spawned threads must exit.

为了避免参数,这里的主题是java.io.InputStream,如Sun(任何Java版本)所述。请注意,这并不像看起来那么简单。以下是Sun的文档直接支持的一些事实。

To avoid arguments, the subject here java.io.InputStream, as documented by Sun (any Java version). Please note this is not as simple as it looks. Below are some facts which are supported directly by Sun's documentation.


  1. in.read()方法可能是不可中断的。

  1. The in.read() method may be non-interruptible.

在Reader或InterruptibleChannel中包装InputStream没有用,因为所有这些类都可以调用InputStream的方法。如果可以使用这些类,就可以编写一个直接在InputStream上执行相同逻辑的解决方案。

Wrapping the InputStream in a Reader or InterruptibleChannel doesn't help, because all those classes can do is call methods of the InputStream. If it were possible to use those classes, it would be possible to write a solution that just executes the same logic directly on the InputStream.

总是可以接受的in.available()返回0。

It is always acceptable for in.available() to return 0.

in.close()方法可能会阻止或什么都不做。

The in.close() method may block or do nothing.

没有通用的方法来杀死另一个线程。

There is no general way to kill another thread.


推荐答案

使用inputStream.available()


系统始终可以接受.in.available()返回0.

我发现相反 - 它总是返回最佳值可用的字节数。 Javadoc for InputStream.available()

I've found the opposite - it always returns the best value for the number of bytes available. Javadoc for InputStream.available():

Returns an estimate of the number of bytes that can be read (or skipped over) 
from this input stream without blocking by the next invocation of a method for 
this input stream.

由于时间/陈旧性,估计是不可避免的。这个数字可能是一次性的低估,因为新的数据不断到来。然而,它总是在接下来的呼叫中赶上 - 它应该考虑所有到达的数据,即刚刚在新呼叫时到达的数据栏。当数据在上述条件下失败时永久返回0。

An estimate is unavoidable due to timing/staleness. The figure can be a one-off underestimate because new data are constantly arriving. However it always "catches up" on the next call - it should account for all arrived data, bar that arriving just at the moment of the new call. Permanently returning 0 when there are data fails the condition above.

第一个警告:InputStream的具体子类负责可用()

InputStream 是一个抽象类。它没有数据源。拥有可用数据对它毫无意义。因此,可用()的javadoc也声明:

InputStream is an abstract class. It has no data source. It's meaningless for it to have available data. Hence, javadoc for available() also states:

The available method for class InputStream always returns 0.

This method should be overridden by subclasses.

实际上,具体的输入流类会覆盖available(),提供有意义的值,而不是常量0 。

And indeed, the concrete input stream classes do override available(), providing meaningful values, not constant 0s.

第二个警告:确保在Windows中输入输入时使用回车符。

如果使用 System.in ,您的程序只会在命令shell交给它时收到输入。如果您正在使用文件重定向/管道(例如somefile> java myJavaApp或somecommand | java myJavaApp),则输入数据通常会立即移交。但是,如果您手动键入输入,则可能会延迟数据切换。例如。使用Windows cmd.exe shell,数据在cmd.exe shell中缓冲。数据仅在回车后传递给执行的java程序(control-m或< enter> )。这是执行环境的限制。当然,只要shell缓冲数据,InputStream.available()就会返回0 - 这是正确的行为;那时没有可用的数据。一旦数据从shell获得,该方法返回一个值> 0.注意:Cygwin也使用cmd.exe。

If using System.in, your program only receives input when your command shell hands it over. If you're using file redirection/pipes (e.g. somefile > java myJavaApp or somecommand | java myJavaApp ), then input data are usually handed over immediately. However, if you manually type input, then data handover can be delayed. E.g. With windows cmd.exe shell, the data are buffered within cmd.exe shell. Data are only passed to the executing java program following carriage-return (control-m or <enter>). That's a limitation of the execution environment. Of course, InputStream.available() will return 0 for as long as the shell buffers the data - that's correct behaviour; there are no available data at that point. As soon as the data are available from the shell, the method returns a value > 0. NB: Cygwin uses cmd.exe too.

只需使用:

    byte[] inputData = new byte[1024];
    int result = is.read(inputData, 0, is.available());  
    // result will indicate number of bytes read; -1 for EOF with no data read.

或等价,

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in, Charset.forName("ISO-8859-1")),1024);
    // ...
         // inside some iteration / processing logic:
         if (br.ready()) {
             int readCount = br.read(inputData, bufferOffset, inputData.length-bufferOffset);
         }



更丰富的解决方案(在超时期限内最大限度地填充缓冲区)



声明:

Richer Solution (maximally fills buffer within timeout period)

Declare this:

public static int readInputStreamWithTimeout(InputStream is, byte[] b, int timeoutMillis)
     throws IOException  {
     int bufferOffset = 0;
     long maxTimeMillis = System.currentTimeMillis() + timeoutMillis;
     while (System.currentTimeMillis() < maxTimeMillis && bufferOffset < b.length) {
         int readLength = java.lang.Math.min(is.available(),b.length-bufferOffset);
         // can alternatively use bufferedReader, guarded by isReady():
         int readResult = is.read(b, bufferOffset, readLength);
         if (readResult == -1) break;
         bufferOffset += readResult;
     }
     return bufferOffset;
 }

然后使用:

    byte[] inputData = new byte[1024];
    int readCount = readInputStreamWithTimeout(System.in, inputData, 6000);  // 6 second timeout
    // readCount will indicate number of bytes read; -1 for EOF with no data read.

这篇关于是否可以从具有超时的InputStream读取?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆