Utilisation de inputStream.available ()
Il est toujours acceptable que System.in.available () renvoie 0.
J'ai trouvé le contraire - il renvoie toujours la meilleure valeur pour le nombre d'octets disponibles. Javadoc pour 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.
Une estimation est inévitable en raison du timing / de l'obsolescence. Le chiffre peut être une sous-estimation ponctuelle car de nouvelles données arrivent constamment. Cependant, il «rattrape» toujours le prochain appel - il doit tenir compte de toutes les données arrivées, sauf celles qui arrivent juste au moment du nouvel appel. Le renvoi permanent de 0 lorsqu'il y a des données échoue à la condition ci-dessus.
Première mise en garde: les sous-classes concrètes d'InputStream sont responsables de available ()
InputStream
est une classe abstraite. Il n'a aucune source de données. Cela n'a aucun sens pour lui d'avoir des données disponibles. Par conséquent, javadoc pour available()
indique également:
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
Et en effet, les classes de flux d'entrée concrètes remplacent available (), fournissant des valeurs significatives, et non des 0 constants.
Deuxième mise en garde: assurez-vous d'utiliser le retour chariot lors de la saisie d'une entrée dans Windows.
Si vous utilisez System.in
, votre programme ne reçoit l'entrée que lorsque votre shell de commande le transmet. Si vous utilisez la redirection de fichiers / tubes (par exemple un fichier> java myJavaApp ou une commande | java myJavaApp), les données d'entrée sont généralement transmises immédiatement. Cependant, si vous tapez manuellement l'entrée, le transfert des données peut être retardé. Par exemple, avec le shell Windows cmd.exe, les données sont mises en mémoire tampon dans le shell cmd.exe. Les données ne sont transmises au programme java en cours d'exécution qu'après un retour chariot (control-m ou <enter>
). C'est une limitation de l'environnement d'exécution. Bien sûr, InputStream.available () renverra 0 tant que le shell met les données en mémoire tampon - c'est un comportement correct; il n'y a pas de données disponibles à ce stade. Dès que les données sont disponibles depuis le shell, la méthode renvoie une valeur> 0. NB: Cygwin utilise cmd.
Solution la plus simple (pas de blocage, donc pas de timeout requis)
Utilisez simplement ceci:
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.
Ou équivalent,
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);
}
Solution plus riche (remplit au maximum le tampon dans le délai d'expiration)
Déclarez ceci:
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;
}
Ensuite, utilisez ceci:
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
cette suggestion échoue. Il y a certainement des flux qui renvoient zéro. SSLSockets par exemple jusqu'à récemment. Vous ne pouvez pas vous y fier.