2010-09-12 16 views
41

¿Qué hace InputStream.available() en Java? Leí la documentación, pero todavía no puedo entenderlo.¿Qué hace InputStream.available() en Java?

El doctor dice:

Devuelve el número de bytes que se pueden leer (o saltadas) de este flujo de entrada sin bloquear por la siguiente llamada de un método de este flujo de entrada. La siguiente persona que llama podría ser el mismo hilo u otro hilo.

El método disponible para la clase InputStream siempre devuelve 0.

¿Qué quieren decir con bloqueo? ¿Significa solo una llamada sincronizada?

Y, sobre todo, ¿cuál es el propósito del método available()?

+1

Hay muy pocos usos realmente útiles de available(). Una de ellas es para leer desde System en. – EJP

Respuesta

24

El bloqueo aquí no está relacionado con el enhebrado o la sincronización. En cambio, se refiere a bloquear IO (ver this para más información). Si emite una solicitud para leer, y el canal no tiene ninguno disponible, una llamada de bloqueo esperará (o bloqueará) hasta que los datos estén disponibles (o el canal esté cerrado, arroje una excepción, etc.)

¿Por qué usar available()? Entonces puede determinar cuántos bytes leer o determinar si va a bloquear.

Tenga en cuenta que Java también tiene capacidades de E/S no bloqueantes. Consulte here para obtener más información

+0

Me encontré con esta pregunta y ahora me pregunto: puedo usar disponible() para resolver mi propio problema, sin recurrir a NIO. Mi pregunta: http://stackoverflow.com/questions/3867042/one-thread-per-client-doable –

+6

Esta respuesta no es correcta. Una llamada de bloqueo se bloqueará mientras haya * datos * no disponibles. Si pides cuatro y hay tres, obtienes tres. – EJP

+0

Ahora es correcto, gracias Brian. – EJP

30

En InputStreams, se dice que las llamadas a read() son llamadas de método "de bloqueo". Eso significa que si no hay datos disponibles en el momento de la llamada al método, el método esperará a que los datos estén disponibles.

El método available() le indica cuántos bytes se pueden leer hasta que la llamada read() bloqueará el flujo de ejecución de su programa. En la mayoría de las secuencias de entrada, todas las llamadas a read() son de bloqueo, por eso es que las disponibles devuelven 0 de manera predeterminada.

Sin embargo, en algunas transmisiones (como BufferedInputStream, que tienen un búfer interno), algunos bytes se leen y guardan en la memoria, por lo que puede leerlos sin bloquear el flujo del programa. En este caso, el método available() le dice cuántos bytes se guardan en el búfer.

+7

BufferedInputStream.available() le dice cuántos bytes se pueden leer sin bloquear. Esta es la * suma * del número de bytes que ya están en el búfer y el resultado() de la secuencia de entrada anidada. Tenga en cuenta también que available() siempre devuelve cero para un socket SSL. – EJP

+0

Lo que no entendí del todo es cuál es el * uso * de saber esto. Realmente, no puedo ver por qué me debería importar, es decir, no puedo ver dónde y cuándo en la aplicación Mu podría encontrar algún uso. Por supuesto, es bastante obvio que estoy siendo ignorante, pero eso es por mi * falta * de experiencia. –

+0

Como dije anteriormente, hay muy pocos usos útiles. Debe saber que está tratando con un flujo que entregará una respuesta distinta de cero y luego debe usar el resultado. – EJP

-2

Considere si escribe software MUY MALO ... y escribe un sistema operativo.

Este sistema operativo toma la entrada del teclado, entre otras cosas.

Así que le pides a tu sistema operativo que vaya y reciba algo del teclado, pero no hay teclas presionadas y ninguna en el búfer. todo su sistema operativo caducará hasta que reciba una entrada de teclado.

Contraste esto con 'mirar hacia adelante', usted pregunta si el KB tiene algún caracter ANTES de hacer la llamada. Usted recibe la respuesta NO, entonces su SO se va y hace otra cosa.

Eso es POR QUÉ debes preocuparte, ahora si luego lo multiplicas por cualquier otra tarea de bloqueo potencial, puedes ver por qué 'mirar hacia adelante' es crítico.

Porque también se aplica a OUTPUT: una memoria en una interfaz de unidad de disco también puede inundar los datos en la unidad de disco más rápido de lo que puede procesarlo. si no sabe que el búfer de unidad está inundado de datos, la tarea se bloqueará hasta que el búfer pueda aceptar más datos.

Esto también resalta el sinsentido de 'hay muy pocos usos útiles'.

+0

No, no es así. No estaba hablando de escribir software muy mal; No estaba hablando de escribir sistemas operativos; No estaba hablando de escribir en una interfaz de unidad de disco: 'disponible()' no te ayuda con la escritura. Estaba hablando de 'InputStream.available()' en *** Java, *** que fue multiproceso la última vez que lo busqué. El único ejemplo válido que da aquí es el mismo que la excepción que mencioné: leer desde el teclado. – EJP

-2

Uno de posiblemente práctico usos de available() lo está utilizando para elegir una longitud de búfer razonable.

static final int LEN = 4096; 

long copy(InputStream in, OutputStream out) throws IOException { 
    int count = 0L; 
    int avl = in.available(); 
    if (avl == 0) { 
     // 0 returned without IOException? possibly mean eof? 
     return 0L; 
    } 
    //byte[] buf = new byte[avl == 0 ? LEN : Math.min(avl, LEN)]; 
    byte[] buf = new byte[Math.min(avl, LEN)]; 
    for (int len; (len = in.read(buf)) != -1; count+= len) { 
     out.write(buf, 0, len); 
    } 
    return count; 
} 

El documento dice,

Devuelve: una estimación del número de bytes que se pueden leer (o saltadas) de este flujo de entrada sin bloquear o 0 cuando llega a la fin de la corriente de entrada.

Y

Una subclase aplicación de este método puede optar por lanzar una IOException si este flujo de entrada se ha cerrado invocando el método close().

ACTUALIZACIÓN

que ya sé la idea no es recomendable. Conozco ese riesgo incluso antes de que el doc. JDK lo advirtiera. (I una vez intentado asignado un tampón de la available de pocos GB dimensionada FileInputStream.)

JDK8/InputStream#available

Nunca es correcta de utilizar el valor de retorno de este método para asignar un búfer destinado para contener todos los datos en esta corriente

JDK5/InputStream#availabe

Pero, en la programación, debe haber ningún código never o always wrong. Eso es lo que estoy creyendo.

+1

No, no y no. Lee el javadoc. "Nunca es correcto usar el valor de retorno de este método para asignar un búfer destinado a contener todos los datos en esta secuencia". – Grod

+0

@Gordon Ya leí el javadoc. Y es por eso que dije * posiblemente-práctico * y usé 'Matemáticas # min'. –

+1

Palabra clave "NUNCA". No importa si crees que es "posiblemente práctico". No lo use de esa manera. Supongamos que tiene 16777216 bytes (16 MiB) para leer. 'available()' podría devolver 4 en el momento en que asignó su búfer. Ahora ha asignado un búfer de 4 bytes y ejecutará ese bucle 4194304 veces. Cuando el javadoc dice "nunca", significa NO HAGAS ESO. – Grod