Utilisation de inputStream.available()
Il est toujours acceptable que System.in.available() renvoie 0.
J'ai constaté 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 calendrier/de l'instabilité. Le chiffre peut être une sous-estimation ponctuelle car de nouvelles données arrivent constamment. Cependant, il se "rattrape" toujours lors de l'appel suivant - il devrait tenir compte de toutes les données arrivées, sauf celles qui arrivent juste au moment du nouvel appel. Le fait de renvoyer en permanence 0 lorsqu'il y a des données ne remplit pas la condition ci-dessus.
Première mise en garde : les sous-classes concrètes de InputStream sont responsables de available()
InputStream
est une classe abstraite. Elle n'a pas de source de données. Il est inutile qu'elle ait des données disponibles. Par conséquent, la javadoc pour available()
déclare é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 surchargent available(), fournissant des valeurs significatives, et non des 0 constants.
Deuxième mise en garde : veillez à utiliser le retour chariot lorsque vous saisissez des données sous Windows.
Si vous utilisez System.in
votre programme ne reçoit des entrées que lorsque votre interpréteur de commandes vous les transmet. Si vous utilisez des redirections de fichiers ou des pipelines (par exemple, somefile > java myJavaApp ou somecommand | java myJavaApp ), les données d'entrée sont généralement transmises immédiatement. Toutefois, si vous tapez manuellement les données d'entrée, le transfert des données peut être retardé. Par exemple, avec l'interpréteur de commandes Windows cmd.exe, les données sont mises en mémoire tampon dans l'interpréteur de commandes cmd.exe. Les données ne sont transmises au programme java en cours d'exécution qu'après un retour de chariot (control-m ou <enter>
). C'est une limitation de l'environnement d'exécution. Bien sûr, InputStream.available() renvoie 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 moment-là. Dès que les données sont disponibles auprès du shell, la méthode renvoie une valeur > 0. NB : Cygwin utilise également cmd.exe.
Solution la plus simple (pas de blocage, donc pas de délai d'attente nécessaire)
Utilisez juste ça :
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 de manière équivalente,
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 imparti)
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;
}
Alors 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.