¿Cómo puedo verificar si un InputStream está vacío sin leerlo?

8 minutos de lectura

avatar de usuario
jenny smith

quiero saber si un InputStream está vacío, pero sin usar el método read(). ¿Hay alguna manera de saber si está vacío sin leerlo?

  • Defina ‘vacío’. ¿Quiere decir ‘al final de la transmisión’ o ‘no hay datos disponibles para leer sin bloquear’?

    – usuario207421

    6 de noviembre de 2014 a las 9:10

avatar de usuario
skaffman

No, no puedes. InputStream está diseñado para trabajar con recursos remotos, por lo que no puede saber si está allí hasta que realmente lo lea.

Es posible que pueda usar un java.io.PushbackInputStreamsin embargo, lo que le permite leer de la secuencia para ver si hay algo allí, y luego “empujarlo hacia atrás” en la secuencia (no es así como funciona realmente, pero así es como se comporta con el código del cliente).

  • PushbackInputStream parece ser la solución más robusta si no sabe con qué tipo de flujo está tratando (es decir, tiene un método que toma un InputStream como argumento).

    – BD en Rivenhill

    23 de agosto de 2011 a las 3:52

  • verifique mi respuesta para un PushbackInputStream basado en implementación: stackoverflow.com/a/19137900/82609

    – Sébastien Lorber

    2 oct 2013 a las 13:21

  • Como se menciona en la documentación del SDK de Android de InputStream.disponible() “El método disponible para la clase InputStream siempre devuelve 0. Este método debe ser anulado por subclases.” lo que implícitamente le dice que llamar available() método en InputStream las instancias en realidad no devolverán nada significativo.

    – Eido95

    14/03/2017 a las 21:38

  • @Eido95 InputStream es abstracto, por lo que todas las instancias son instancias de subclases (que, según el documento, deberían anular el método).

    – rolve

    3 de marzo de 2021 a las 21:43

avatar de usuario
vpram86

creo que estas buscando inputstream.available(). No le dice si está vacío, pero puede darle una indicación de si hay datos para leer o no.

  • available() le dice si hay datos listos para ser leídos, no necesariamente le dice si la transmisión está vacía.

    – Skaffman

    6 de octubre de 2009 a las 8:37

  • @skaffman: ¡muchas gracias! Pensé que era suficiente :). Edité mi respuesta para reflejarla.

    – vpram86

    6 de octubre de 2009 a las 8:40

  • available() no hizo exactamente lo que necesitaba, pero fue la solución más cercana.

    – Jenny Smith

    6 de octubre de 2009 a las 11:58

  • “no hice exactamente lo que necesitaba” ¿qué es lo que necesitas en realidad? ¿Es para asignar un búfer antes de cargarlo, o…?

    – penpen

    6 de octubre de 2009 a las 17:26

  • votar por la respuesta. boo java para nombrar está disponible, lo que parece que debería ser un booleano, no un int.

    – granadaCoder

    26 de enero de 2021 a las 22:59

Basado en la sugerencia de usar PushbackInputStream, aquí encontrará una implementación de ejemplo:

/**
 * @author Lorber Sebastien <i>(lorber.sebastien@gmail.com)</i>
 */
public class NonEmptyInputStream extends FilterInputStream {

  /**
   * Once this stream has been created, do not consume the original InputStream 
   * because there will be one missing byte...
   * @param originalInputStream
   * @throws IOException
   * @throws EmptyInputStreamException
   */
  public NonEmptyInputStream(InputStream originalInputStream) throws IOException, EmptyInputStreamException {
    super( checkStreamIsNotEmpty(originalInputStream) );
  }


  /**
   * Permits to check the InputStream is empty or not
   * Please note that only the returned InputStream must be consummed.
   *
   * see:
   * http://stackoverflow.com/questions/1524299/how-can-i-check-if-an-inputstream-is-empty-without-reading-from-it
   *
   * @param inputStream
   * @return
   */
  private static InputStream checkStreamIsNotEmpty(InputStream inputStream) throws IOException, EmptyInputStreamException {
    Preconditions.checkArgument(inputStream != null,"The InputStream is mandatory");
    PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
    int b;
    b = pushbackInputStream.read();
    if ( b == -1 ) {
      throw new EmptyInputStreamException("No byte can be read from stream " + inputStream);
    }
    pushbackInputStream.unread(b);
    return pushbackInputStream;
  }

  public static class EmptyInputStreamException extends RuntimeException {
    public EmptyInputStreamException(String message) {
      super(message);
    }
  }

}

Y aquí hay algunas pruebas de aprobación:

  @Test(expected = EmptyInputStreamException.class)
  public void test_check_empty_input_stream_raises_exception_for_empty_stream() throws IOException {
    InputStream emptyStream = new ByteArrayInputStream(new byte[0]);
    new NonEmptyInputStream(emptyStream);
  }

  @Test
  public void test_check_empty_input_stream_ok_for_non_empty_stream_and_returned_stream_can_be_consummed_fully() throws IOException {
    String streamContent = "HELLooooô wörld";
    InputStream inputStream = IOUtils.toInputStream(streamContent, StandardCharsets.UTF_8);
    inputStream = new NonEmptyInputStream(inputStream);
    assertThat(IOUtils.toString(inputStream,StandardCharsets.UTF_8)).isEqualTo(streamContent);
  }

  • La pregunta dice específicamente ‘sin usar el método read()‘ y ‘sin leer de él’.

    – usuario207421

    6 de noviembre de 2014 a las 9:09

  • @EJP conceptualmente, no puede saber si una transmisión está vacía sin haber recibido algo si no tiene ninguna otra información relacionada con esa transmisión (por ejemplo, en transmisiones HTTP, el Content-Size encabezamiento. Entonces, tal vez podamos asumir que el autor de la pregunta entiende eso y solo quiere verificar si la secuencia está vacía y aún puede leerla desde el principio.

    – Sébastien Lorber

    6 de noviembre de 2014 a las 11:27


  • Estoy completamente de acuerdo, pero esa es la restricción especificada en la pregunta, y tampoco ha respondido a las solicitudes de su definición de ‘vacío’.

    – usuario207421

    8 de noviembre de 2017 a las 9:22


avatar de usuario
Henning

Si el InputStream está utilizando soporte para marcar/restablecer, también puede intentar leer el primer byte de la secuencia y luego restablecerlo a su posición original:

input.mark(1);
final int bytesRead = input.read(new byte[1]);
input.reset();
if (bytesRead != -1) {
    //stream not empty
} else {
    //stream empty
} 

Si no controlas qué tipo de InputStream estás usando, puedes usar el markSupported() método para verificar si marcar/restablecer funcionará en la transmisión y recurrir al available() método o el java.io.PushbackInputStream método de otra manera.

Puedes usar el available() método para preguntar a la transmisión si hay datos disponibles en el momento lo llamas. Sin embargo, no se garantiza que esa función funcione en todos los tipos de flujos de entrada. Eso significa que no puedes usar available() para determinar si una llamada a read() realmente bloqueará o no.

  • Indique un caso en el que available() no funcione correctamente.

    – Jenny Smith

    7 de octubre de 2009 a las 6:19

  • El método available() de InputStream devuelve 0 de forma predeterminada; si una subclase no anula este método, siempre se devolverá 0.

    – Greg Hewgill

    7 de octubre de 2009 a las 6:28

  • … Sé que no funciona en un socket SSL, pero este no es mi caso.

    – Jenny Smith

    7 de octubre de 2009 a las 6:28

  • Sí, lo sé de forma predeterminada devuelve 0, pero en el Javadoc, todas las subclases de la clase InputStream tienen el método disponible () anulando el método en la superclase y devolviendo la cantidad de bytes disponibles en la secuencia.

    – Jenny Smith

    7 de octubre de 2009 a las 6:34

  • @JennySmith Eso es simplemente falso. El Javadoc para la mayoría de los available() métodos simplemente establece que devuelve in.available(), lo que sea que pueda hacer. DataInputStream ni siquiera implementa available() en absoluto. PushbackInputStream.available() solo garantiza devolver un valor distinto de cero si los datos se han retrocedido. StringBufferInputStream es el único otro que puedo encontrar que definitivamente siempre puede devolver un valor distinto de cero.

    – usuario207421

    13 de octubre de 2014 a las 2:44

¿Qué hay de usar inputStreamReader.listo() ¿descubrir?

import java.io.InputStreamReader;

/// ...

InputStreamReader reader = new InputStreamReader(inputStream);
if (reader.ready()) {
    // do something
}

// ...

  • Indique un caso en el que available() no funcione correctamente.

    – Jenny Smith

    7 de octubre de 2009 a las 6:19

  • El método available() de InputStream devuelve 0 de forma predeterminada; si una subclase no anula este método, siempre se devolverá 0.

    – Greg Hewgill

    7 de octubre de 2009 a las 6:28

  • … Sé que no funciona en un socket SSL, pero este no es mi caso.

    – Jenny Smith

    7 de octubre de 2009 a las 6:28

  • Sí, lo sé de forma predeterminada devuelve 0, pero en el Javadoc, todas las subclases de la clase InputStream tienen el método disponible () anulando el método en la superclase y devolviendo la cantidad de bytes disponibles en la secuencia.

    – Jenny Smith

    7 de octubre de 2009 a las 6:34

  • @JennySmith Eso es simplemente falso. El Javadoc para la mayoría de los available() métodos simplemente establece que devuelve in.available(), lo que sea que pueda hacer. DataInputStream ni siquiera implementa available() en absoluto. PushbackInputStream.available() solo garantiza devolver un valor distinto de cero si los datos se han retrocedido. StringBufferInputStream es el único otro que puedo encontrar que definitivamente siempre puede devolver un valor distinto de cero.

    – usuario207421

    13 de octubre de 2014 a las 2:44

Sin leer no puedes hacer esto. Pero puede usar una solución alternativa como la siguiente.

Puedes usar Marcos() y Reiniciar() métodos para hacer esto.

El método mark(int readlimit) marca la posición actual en este flujo de entrada.

El método reset () reposiciona este flujo a la posición en el momento en que se llamó por última vez al método de marca en este flujo de entrada.

Antes de que pueda usar la marca y el restablecimiento, debe probar si estas operaciones son compatibles con el flujo de entrada que está leyendo. Puede hacerlo con markSupported.

El método de marca acepta un límite (entero), que denota el número máximo de bytes que se leerán por adelantado. Si lee más de este límite, no puede volver a esta marca.

Para aplicar estas funcionalidades para este caso de uso, debemos marcar la posición como 0 y luego leer el flujo de entrada. Luego, debemos restablecer el flujo de entrada y el flujo de entrada se revertirá al original.

    if (inputStream.markSupported()) {
          inputStream.mark(0);
          if (inputStream.read() != -1) {
               inputStream.reset();
          } else {
               //Inputstream is empty
          }
    }

Aquí, si el flujo de entrada está vacío, el método read() devolverá -1.

¿Ha sido útil esta solución?