Menggunakan inputStream.available ()
Itu selalu dapat diterima untuk System.in.available () untuk mengembalikan 0.
Saya telah menemukan yang sebaliknya - selalu mengembalikan nilai terbaik untuk jumlah byte yang tersedia. Javadoc untuk 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.
Estimasi tidak dapat dihindari karena waktu / staleness. Angka tersebut bisa menjadi perkiraan sekali saja karena data baru terus berdatangan. Namun itu selalu "mengejar" pada panggilan berikutnya - itu harus memperhitungkan semua data yang tiba, bar yang tiba tepat pada saat panggilan baru. Mengembalikan 0 secara permanen ketika ada data yang gagal dengan kondisi di atas.
Peringatan Pertama: Subkelas beton InputStream bertanggung jawab atas ketersediaan ()
InputStream
adalah kelas abstrak. Tidak memiliki sumber data. Tidak ada artinya untuk memiliki data yang tersedia. Karenanya, javadoc untuk available()
juga menyatakan:
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
Dan memang, kelas stream input konkret melakukan override available (), memberikan nilai yang bermakna, bukan 0s konstan.
Peringatan Kedua: Pastikan Anda menggunakan carriage-return saat mengetik input di Windows.
Jika menggunakan System.in
, program Anda hanya menerima input ketika shell perintah Anda menyerahkannya. Jika Anda menggunakan pengalihan file / pipa (mis. Somefile> java myJavaApp atau somecommand | java myJavaApp), maka input data biasanya diserahkan segera. Namun, jika Anda mengetik input secara manual, maka penyerahan data dapat ditunda. Misalnya Dengan shell windows cmd.exe, data di buffer dalam shell cmd.exe. Data hanya diteruskan ke program java yang menjalankan mengikuti carriage-return (control-m atau <enter>
). Itu batasan lingkungan eksekusi. Tentu saja, InputStream.available () akan mengembalikan 0 selama shell buffer data - itu perilaku yang benar; tidak ada data yang tersedia pada saat itu. Segera setelah data tersedia dari shell, metode mengembalikan nilai> 0. NB: Cygwin menggunakan cmd.
Solusi paling sederhana (tidak ada pemblokiran, jadi tidak perlu waktu habis)
Gunakan ini saja:
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.
ATAU setara,
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 (secara maksimal mengisi buffer dalam periode waktu habis)
Nyatakan ini:
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;
}
Kemudian gunakan ini:
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
saran ini akan gagal. Tentu saja ada aliran yang mengembalikan nol. SSLSockets misalnya hingga saat ini. Anda tidak dapat mengandalkan ini.