Usando inputStream.available ()
Siempre es aceptable que System.in.available () devuelva 0.
He encontrado lo contrario: siempre devuelve el mejor valor para la cantidad de bytes disponibles. Javadoc para 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 estimación es inevitable debido al tiempo / estancamiento. La cifra puede ser una subestimación única porque constantemente llegan nuevos datos. Sin embargo, siempre "se pone al día" en la próxima llamada: debe tener en cuenta todos los datos recibidos, salvo el que llega justo en el momento de la nueva llamada. Devolver permanentemente 0 cuando hay datos falla la condición anterior.
Primera advertencia: las subclases concretas de InputStream son responsables de las disponibles ()
InputStream
Es una clase abstracta. No tiene fuente de datos. No tiene sentido tener datos disponibles. Por lo tanto, javadoc para available()
también afirma:
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
Y, de hecho, las clases concretas de flujo de entrada anulan disponible (), proporcionando valores significativos, no ceros constantes.
Segunda advertencia: asegúrese de utilizar el retorno de carro al escribir la entrada en Windows.
Si lo usa System.in
, su programa solo recibe información cuando su shell de comando lo entrega. Si está utilizando redirección / canalización de archivos (por ejemplo, algún archivo> java myJavaApp o somecommand | java myJavaApp), los datos de entrada generalmente se entregan de inmediato. Sin embargo, si escribe manualmente la entrada, la transferencia de datos puede retrasarse. Por ejemplo, con el shell cmd.exe de Windows, los datos se almacenan en el shell cmd.exe. Los datos solo se pasan al programa Java en ejecución después del retorno de carro (control-mo <enter>
). Esa es una limitación del entorno de ejecución. Por supuesto, InputStream.available () devolverá 0 durante el tiempo que el shell guarde los datos, es el comportamiento correcto; No hay datos disponibles en ese momento. Tan pronto como los datos estén disponibles desde el shell, el método devuelve un valor> 0. NB: Cygwin usa cmd.
La solución más simple (sin bloqueo, por lo que no se requiere tiempo de espera)
Solo usa esto:
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 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);
}
Solución más rica (llena al máximo el búfer dentro del tiempo de espera)
Declara esto:
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;
}
Entonces usa esto:
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
esta sugerencia fallará. Ciertamente, hay flujos que devuelven cero. SSLSockets, por ejemplo, hasta hace poco. No puedes confiar en esto.