inputStream.available()の使用
System.in.available()が0を返すことは常に許容されます。
私は反対を見つけました-それは常に利用可能なバイト数の最良の値を返します。のJavadoc 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.
タイミング/古さのため、見積もりは避けられません。新しいデータが常に到着しているため、この数値は1回限りの過小評価になる可能性があります。ただし、次の呼び出しでは常に「追いつきます」-新しい呼び出しの瞬間に到着したものではなく、到着したすべてのデータを考慮しなければなりません。データがあるときに永続的に0を返すと、上記の条件が満たされなくなります。
最初の注意:InputStreamの具象サブクラスはavailable()を担当します
InputStream
抽象クラスです。データソースがありません。利用可能なデータがあることは意味がありません。したがって、のjavadocにavailable()
も次のように記載されています。
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
そして実際、具象入力ストリームクラスはavailable()をオーバーライドし、定数0ではなく意味のある値を提供します。
2番目の警告:Windowsで入力を入力するときは、必ずキャリッジリターンを使用してください。
を使用しているSystem.in
場合、コマンドシェルがプログラムを渡したときにのみ、プログラムは入力を受け取ります。ファイルリダイレクト/パイプを使用している場合(例:somefile> java myJavaAppまたはsomecommand | java myJavaApp)、入力データは通常すぐに渡されます。ただし、手動で入力を入力すると、データの受け渡しが遅れる可能性があります。たとえば、Windowsのcmd.exeシェルでは、データはcmd.exeシェル内でバッファリングされます。データは、キャリッジリターン(control-mまたは<enter>
)に続いて実行中のJavaプログラムにのみ渡されます。これは実行環境の制限です。もちろん、InputStream.available()は、シェルがデータをバッファリングしている限り0を返します-これは正しい動作です。その時点で利用可能なデータはありません。シェルからデータが利用可能になるとすぐに、メソッドは> 0の値を返します。注意:Cygwinはcmdを使用します。
最も簡単なソリューション(ブロッキングがないため、タイムアウトは不要)
これを使うだけです:
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.
is.available() > 1024
、この提案は失敗します。確かにゼロを返すストリームがあります。たとえば最近までSSLSockets。これに頼ることはできません。