使用 inputStream.available()
System.in.available() 返回 0 始终是可以接受的。
我发现相反 - 它总是返回可用字节数的最佳值。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。
第一个警告:InputStream的具体子类负责可用()
InputStream
是一个抽象类。它没有数据源。对于它来说,拥有可用的数据是没有意义的。因此,javadoc for 也声明:available()
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
事实上,具体的输入流类确实覆盖了 available(),提供了有意义的值,而不是常量 0。
第二个警告:确保在 Windows 中键入输入时使用回车符。
如果使用 ,则仅当命令 shell 交出输入时,程序才会接收输入。如果您使用的是文件重定向/管道(例如,>java myJavaApp或java myJavaApp|某些命令),则输入数据通常会立即移交。但是,如果手动键入输入,则数据切换可能会延迟。例如,使用windows cmd.exe shell,数据在cmd.exe shell中缓冲。数据仅在回车(control-m 或 )之后传递到正在执行的 java 程序。这是执行环境的局限性。当然,InputStream.available() 将返回 0,只要 shell 缓冲数据 - 这是正确的行为;此时没有可用的数据。一旦数据从 shell 中可用,该方法将返回一个值 > 0。注意:Cygwin也使用cmd.exe。System.in
<enter>
最简单的解决方案(无阻塞,因此无需超时)
只需使用这个:
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);
}
更丰富的解决方案(在超时期限内最大限度地填充缓冲区)
声明如下:
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.