Utilizzo di inputStream.available ()
È sempre accettabile che System.in.available () restituisca 0.
Ho trovato il contrario: restituisce sempre il valore migliore per il numero di byte disponibili. Javadoc per 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.
Una stima è inevitabile a causa di tempismo / staleness. La cifra può essere una sottovalutazione una tantum perché arrivano costantemente nuovi dati. Tuttavia, "raggiunge" sempre la chiamata successiva: dovrebbe tenere conto di tutti i dati arrivati, escluso quello in arrivo al momento della nuova chiamata. Restituendo permanentemente 0 quando ci sono dati non riesce la condizione sopra.
Primo avvertimento: sottoclassi concrete di InputStream sono responsabili per disponibili ()
InputStream
è una classe astratta. Non ha un'origine dati. Non ha senso avere dati disponibili. Quindi, Javadoc peravailable()
afferma anche:
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
E in effetti, le classi concrete del flusso di input sovrascrivono available (), fornendo valori significativi, non 0 costanti.
Secondo avvertimento: assicurarsi di utilizzare il ritorno a capo quando si digita l'input in Windows.
Se si utilizza System.in
, il programma riceve input solo quando la shell dei comandi lo consegna. Se stai utilizzando il reindirizzamento dei file / pipe (ad esempio somefile> java myJavaApp o somecommand | java myJavaApp), i dati di input vengono generalmente consegnati immediatamente. Tuttavia, se si digita manualmente l'input, la consegna dei dati può essere ritardata. Ad esempio con la shell di cmd.exe di Windows, i dati vengono bufferizzati nella shell di cmd.exe. I dati vengono passati al programma java in esecuzione solo dopo il ritorno a capo (control-m o<enter>
). Questa è una limitazione dell'ambiente di esecuzione. Ovviamente, InputStream.available () restituirà 0 fintanto che la shell esegue il buffering dei dati - questo è un comportamento corretto; non ci sono dati disponibili a quel punto. Non appena i dati sono disponibili dalla shell, il metodo restituisce un valore> 0. NB: Cygwin utilizza cmd.
Soluzione più semplice (nessun blocco, quindi nessun timeout richiesto)
Usa questo:
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.
O in modo equivalente,
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);
}
Soluzione più ricca (riempie al massimo il buffer entro il periodo di timeout)
Dichiara questo:
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;
}
Quindi usa questo:
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
questo suggerimento fallirà. Ci sono certamente flussi che restituiscono zero. SSLSocket per esempio fino a poco tempo fa. Non puoi fare affidamento su questo.