使用inputStream.available()
System.in.available() 返回 0 始终是可以接受的。
我发现相反的情况 - 它总是返回可用字节数的最佳值。根据 InputStream.available()
的JavaDoc:
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,则无法满足以上条件。
第一个注意点:具体的InputStream
子类负责available()
InputStream
是一个抽象类。它没有数据源。它拥有可用数据是毫无意义的。因此,available()
的javadoc也说明:
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
实际上,具体的输入流类确实覆盖了available()方法,提供有意义的值而不是常数0。
第二个警告:在Windows中键入输入时,请确保使用回车符。
如果使用System.in
,则当您的命令行程序将其传递时,您的程序才会收到输入。如果您正在使用文件重定向/管道(例如somefile > java myJavaApp或somecommand | java myJavaApp),则输入数据通常会立即传递。但是,如果您手动输入数据,则数据传递可能会延迟。例如,在Windows cmd.exe shell中,数据会缓冲在cmd.exe shell中。只有在按下回车键(控制-M或<enter>
)后,数据才会传递给执行的Java程序。这是执行环境的限制。当然,InputStream.available()在shell缓冲数据时将返回0 - 这是正确的行为;此时没有可用的数据。一旦数据从shell可用,该方法将返回一个大于0的值。注意:Cygwin也使用cmd.exe。
最简单的解决方案(无阻塞,因此不需要超时)
只需使用以下内容:
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);
if (br.ready()) {
int readCount = br.read(inputData, bufferOffset, inputData.length-bufferOffset);
}
更丰富的解决方案(在超时期限内最大程度地填充缓冲区)
声明如下:
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);
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.
is.available() > 1024
,这个建议将会失败。当然有一些流(streams)确实会返回0,例如直到最近的SSLSockets也是如此。你不能依赖这一点。 - user207421