English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Estudio de Java IO: Flujo de entrada en缓冲(BufferedInputStream)

Java IO BufferedInputStream

Resumen:

BufferedInputStream es un flujo de entrada en缓冲,heredado de FilterInputStream, su función es agregar algunas características a otro flujo de entrada, esencialmente implementado mediante un array de buffer interno. Por ejemplo, después de crear un BufferedInputStream correspondiente a un flujo de entrada, cuando se lee datos a través de read(), BufferedInputStream llenará los datos del flujo de entrada por lotes en el buffer, cada vez que se lean los datos del buffer, el flujo de entrada llenará el buffer de datos nuevamente hasta que se lean todos los datos.

Lista principal de funciones de BufferedInputStream:

BufferedInputStream(InputStream in) 
BufferedInputStream(InputStream in, int size) 
synchronized int available() 
void close() 
synchronized void mark(int readlimit) 
boolean markSupported() 
synchronized int read() 
synchronized int read(byte[] buffer, int offset, int byteCount) 
synchronized void reset() 
synchronized long skip(long byteCount) 

Ejemplo de código:

public class BufferedInputStreamTest { 
  private static final int LEN = 5; 
  public static void main(String[] args) { 
    testBufferedInputStream() ; 
  } 
  private static void testBufferedInputStream() { 
    // Crear el flujo de bytes BufferedInputStream, contenido en el array ArrayLetters 
    try { 
      File file = new File("file.txt"); 
      InputStream in =new BufferedInputStream(new FileInputStream(file), 512); 
      // lectura desde el flujo de bytes5bytes. "abcde", a corresponde a 0x61b corresponde a 0x62y así sucesivamente... 
      for (int i=0; i<LEN; i++) { 
      // Si se puede leer el siguiente byte, leer el siguiente byte 
        if (in.available() >= 0) { 
        // Lectura del siguiente byte del flujo de bytes 
        int tmp = in.read(); 
        System.out.printf("%d : 0x%s\n", i, Integer.toHexString(tmp)); 
        } 
      } 
      // Si el flujo de bytes no admite la función de marcado, salir directamente 
      if (!in.markSupported()) { 
        System.out.println("make not supported!"); 
        return ; 
      } 
      // Marcar la posición de índice actual, es decir, marcar el6elementos en la posición--"f" 
      // 1024correspondiente a marklimit 
      in.mark(1024); 
      // Saltar22de bytes. 
      in.skip(22); 
      // lectura5de bytes 
      byte[] buf = new byte[LEN]; 
      in.read(buf, 0, LEN); 
      // Convertir buf a una cadena de String. 
      String str1 = new String(buf); 
      System.out.printf("str1=%s\n", str1); 
      // Restablecer el índice de la entrada de flujo a la posición marcada por mark(), es decir, restablecer a 'f'. 
      in.reset(); 
      // leer desde el "flujo de bytes resetado"5bytes a buf. Es decir, leer "fghij" 
      in.read(buf, 0, LEN); 
      // Convertir buf a una cadena de String. 
      String str2 = new String(buf); 
      System.out.printf("str2=%s\n", str2); 
      in.close(); 
    } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
    } catch (SecurityException e) { 
      e.printStackTrace(); 
    } catch (IOException e) { 
      e.printStackTrace(); 
    } 
  } 
} 

Resultados de ejecución:

0 : 0x61
1 : 0x62
2 : 0x63
3 : 0x64
4 : 0x65
str1=12345
str2=fghij

basado en JDK8el código de BufferInputStream:

public class BufferedInputStream extends FilterInputStream { 
  private static int DEFAULT_BUFFER_SIZE = 8192;//El tamaño del buffer predeterminado es8X1024 
  private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; 
  protected volatile byte buf[]; //arreglo de buffer 
  /** 
   * Atomic updater para proporcionar compareAndSet para buf. Esto es 
   * necesario porque los cierres pueden ser asíncronos. Usamos nullness 
   * de buf[] como indicador principal de que este flujo está cerrado. (The 
   * "in" el campo también se nuliza al cerrar.) 
   */ 
  private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = 
      AtomicReferenceFieldUpdater.newUpdater(BufferedInputStream.class, byte[].class, "buf"); 
  //El valor está entre 0 y buf.len 
  protected int count; 
  //the next character to be read is at the current position in the buffer 
  protected int pos; 
  //The value is the value of the mark function when it was last called, the value is-1to pos 
  protected int markpos = -1; 
  /** 
   * The maximum read ahead allowed after a call to the 
   * <code>mark</code> method before subsequent calls to the 
   * <code>reset</code> method fail. 
   * Whenever the difference between <code>pos</código> 
   * and <code>markpos</code> exceeds <code>marklimit</code>, 
   * then the mark may be dropped by setting 
   * <code>markpos</code> to <code>-1</código>. 
   * 
   * @see java.io.BufferedInputStream#mark(int) 
   * @see   java.io.BufferedInputStream#reset() 
   */ 
  protected int marklimit; 
  /** 
   * Check to make sure that underlying input stream has not been 
   * nulled out due to close; if not return it; 
   */ 
  // 
  private InputStream getInIfOpen() throws IOException { 
    InputStream input = in; 
    if (input == null) 
      lanzar nueva IOException("El flujo se cerró"); 
    return input; 
  } 
  /** 
   * Check to make sure that buffer has not been nulled out due to 
   * close; if not return it; 
   */ 
  private byte[] getBufIfOpen() throws IOException { 
    byte[] buffer = buf; 
    if (buffer == null) 
      lanzar nueva IOException("El flujo se cerró"); 
    return buffer; 
  } 
  /** 
   * Crea un <code>BufferedInputStream</código> 
   * y guarda su argumento, el flujo de entrada 
   * <code>in</code>, para su uso posterior. Un interno 
   * buffer array is created and stored in <code>buf</código>. 
   * 
   * @param in the underlying input stream. 
   */ 
  //Constructor con InputStream 
  public BufferedInputStream(InputStream in) { 
      this(in, DEFAULT_BUFFER_SIZE); 
  } 
  /** 
   * Crea un <code>BufferedInputStream</código> 
   * con el tamaño de búfer especificado, 
   * y guarda su argumento, el flujo de entrada 
   * <code>in</code>, para su uso posterior. Un interno 
   * matriz de búfer de longitud <code>size</código> 
   * se crea y se almacena en <code>buf</código>. 
   * 
   * @param  in   el flujo de entrada subyacente. 
   * @param  size  el tamaño del búfer. 
   * @exception IllegalArgumentException si {@code size <= 0}. 
   */ 
  //Constructor con InputStream y tamaño 
  public BufferedInputStream(InputStream in, int size) { 
    super(in); 
    if (size <= 0) { 
        lanza new IllegalArgumentException("Tamaño del búfer <= 0"); 
    } 
    buf = new byte[size]; 
  } 
  /** 
   * Llena el búfer con más datos, teniendo en cuenta 
   * mezclando y otros trucos para manejar marcas. 
   * Asume que está siendo llamado por un método sincronizado. 
   * Este método también asume que todos los datos ya han sido leídos, 
   * por lo tanto, pos > count. 
   */ 
  // 
  private void fill() throws IOException { 
    byte[] buffer = getBufIfOpen(); 
    si (markpos < 0) 
      pos = 0;      /* no hay marca: desechar el búfer */ 
    si no (pos >= buffer.length) /* no hay espacio restante en el búfer */ 
      si (markpos > 0) { /* puede desechar la parte inicial del búfer */ 
        int sz = pos - markpos; 
        System.arraycopy(buffer, markpos, buffer, 0, sz); 
        pos = sz; 
        markpos = 0; 
      } 
         markpos = -1;  /* el búfer se hizo demasiado grande, invalidar marca */ 
         pos = 0;    /* descartar el contenido del búfer */ 
      } else si (buffer.length >= MAX_BUFFER_SIZE) { 
        lanzar nueva OutOfMemoryError("El tamaño del array requerido es demasiado grande"); 
      } else {      /* aumentar el tamaño del búfer */ 
        int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? 
        pos * 2 : MAX_BUFFER_SIZE; 
        si (nsz > marklimit) 
          nsz = marklimit; 
        byte nbuf[] = new byte[nsz]; 
        System.arraycopy(buffer, 0, nbuf, 0, pos); 
        si (!bufUpdater.compareAndSet(this, buffer, nbuf)) { 
          // No se puede reemplazar buf si hubo un cierre asíncrono. 
          // Nota: Esto tendría que cambiarse si fill() 
          // siempre se hace accesible a múltiples hilos. 
          // Pero por ahora, la única manera en que CAS puede fallar es a través de close. 
          // afirmar que buf == null; 
          lanzar nueva IOException("El flujo se cerró"); 
        } 
        buffer = nbuf; 
      } 
    cuenta = pos; 
    int n = getInIfOpen().read(buffer, pos, buffer.length - pos); 
    if (n > 0) 
      cuenta = n + pos; 
    } 
  /** 
   * Ver 
   * el contrato general del <code>read</código> 
   * método de <código>InputStream</código>. 
   * 
   * @return   el siguiente byte de datos, o <code>-1</code> si el final del 
   *       el flujo se alcanza. 
   * @exception IOException si este flujo de entrada ha sido cerrado por 
   *             invocando su método {@link #close()}, 
   *             o un I/Ocurre un error. 
   * @see    java.io.FilterInputStream#in 
   */ 
  //leer el siguiente byte, no hay datos para retornar-1 
  public synchronized int read() throws IOException { 
    if (pos >= cuenta) { 
      llenar(); 
      if (pos >= cuenta) 
        return -1; 
    } 
    return getBufIfOpen()[pos++] & 0xff; 
  } 
  /** 
   * Leer caracteres en una parte de un array, leyendo desde el flujo subyacente 
   * leer el flujo una vez si es necesario. 
   */ 
  private int read1(byte[] b, int off, int longitud) throws IOException { 
    int disponible = cuenta - pos; 
    si (disponible <= 0) { 
      /* Si la longitud solicitada es al menos tan grande como el búfer, y 
        si no hay marca/restablecer la actividad, no molestar a copiar el 
        bytes en el búfer local. De esta manera, los flujos en búfer 
        hacer daño sin consecuencias. */ 
      if (longitud >= getBufIfOpen().length && markpos < 0) { 
        return getInIfOpen().read(b, off, len); 
      } 
      llenar(); 
      disponible = cuenta - pos; 
      if (disponible <= 0) return -1; 
    } 
    int cnt = (avail < len) ?63; avail : len; 
    System.arraycopy(getBufIfOpen(), pos, b, off, cnt); 
    pos += cnt; 
    devuelve cnt; 
  } 
  /** 
   * Lee bytes desde este byte-flujo de entrada al array de bytes especificado, 
   * comenzando en el desplazamiento dado. 
   * 
   * <p> Este método implementa el contrato general correspondiente 
   * <code>{@link InputStream#read(byte[], int, int) read}</<code> método de 
   * el <code>{@link InputStream}</<code> clase. Como una adición adicional 
   * por conveniencia, intenta leer tantos bytes como sea posible mediante la repetición 
   * invocando el <code>read</<code> método del flujo subyacente. Esto 
   * iteraciones <code>read</<code>continúa hasta que una de las siguientes 
   * las condiciones se vuelven verdaderas: <ul> 
   * 
   *  <li> Se han leído el número especificado de bytes, 
   * 
   *  <li> El <code>read</<code> método del flujo subyacente devuelve 
   *  <code>-1</<code>, lo que indica el final-of-archivo, o 
   * 
   *  <li> El <code>available</método del flujo subyacente 
   *  devuelve cero, lo que indica que las solicitudes de entrada adicionales bloquearán. 
   * 
   * </ul> Si el primer <code>read</code> on the underlying stream returns 
   * <code>-1</code> to indicate end-of-file then this method returns 
   * <code>-1</code>. Otherwise this method returns the number of bytes 
   * actually read. 
   * 
   * <p> Subclasses of this class are encouraged, but not required, to 
   * attempt to read as many bytes as possible in the same fashion. 
   * 
   * @param   b   destination buffer. 
   * @param   off  offset at which to start storing bytes. 
   * @param   len  maximum number of bytes to read. 
   * @return   the number of bytes read, or <code>-1</code> if the end of 
   *       the stream has been reached. 
   * @exception IOException si este flujo de entrada ha sido cerrado por 
   *             invocando su método {@link #close()}, 
   *             o un I/Ocurre un error. 
   */ 
  // 
  public synchronized int read(byte b[], int off, int len)throws IOException 
  { 
    getBufIfOpen(); // Verificar el flujo cerrado 
    if ((off | len | (off + len) | (b.length - (off + len))) < 0) { 
      throw new IndexOutOfBoundsException(); 
    } else if (len == 0) { 
      devolver 0; 
    } 
    int n = 0; 
    for (;;) { 
      int nread = read1(b, off + n, len - n); 
      if (nread <= 0) 
        return (n == 0) ? nread : n; 
      n += nread; 
      if (n >= len) 
        devolver n; 
      // if not closed but no bytes available, return 
      InputStream input = in; 
      if (input != null && input.available() <= 0) 
        devolver n; 
    } 
  } 
  /** 
   * Ver el contrato general de <code>skip</code>/código> 
   * método de <código>InputStream</código>. 
   * 
   * @exception IOException si el flujo no admite seek, 
   *             o si este flujo de entrada ha sido cerrado por 
   *             invocando su método {@link #close()}, o un 
   *             I/Ocurre un error. 
   */ 
  //saltar datos de longitud n 
  public synchronized long omitir(long n) throws IOException { 
    getBufIfOpen(); // Verificar el flujo cerrado 
    si (n <= 0) { 
      devolver 0; 
    } 
    long disponible = cuenta - pos; 
    si (disponible <= 0) { 
      // Si no se ha establecido una posición de marca, no se debe mantener en el búfer 
      si (markpos < 0) 
        devolver getInIfOpen().omitir(n); 
      // Llenar el búfer para ahorrar bytes para restablecer 
      llenar(); 
      disponible = cuenta - pos; 
      si (disponible <= 0) 
        devolver 0; 
    } 
    long omitido = (disponible < n) ?63; disponible : n; 
    pos += omitido; 
    devolver omitido; 
  } 
  /** 
   * Devuelve una estimación del número de bytes que se pueden leer (o 
   * omitido) de este flujo de entrada sin bloquearse por el siguiente 
   * invocación de un método para este flujo de entrada. La próxima invocación podría ser 
   * la misma hebra o otra hebra. Una sola lectura o omisión de este 
   * muchos bytes no bloquearán, pero pueden leer o omitir menos bytes. 
   * <p> 
   * Este método devuelve la suma del número de bytes restantes por leer en 
   * el búfer (<code>count - pos</code>) y el resultado de llamar a la 
   * {@link java.io.FilterInputStream#in in}.available(). 
   * 
   * @return   una estimación del número de bytes que se pueden leer (o omitir 
   *       sobre) desde este flujo de entrada sin bloquear. 
   * @exception IOException si este flujo de entrada ha sido cerrado por 
   *             invocando su método {@link #close()}, 
   *             o un I/Ocurre un error. 
   */ 
  //devuelve cuántos datos hay que leer 
  public synchronized int available() throws IOException { 
    int n = count - pos; 
    int avail = getInIfOpen().available(); 
    return n > (Integer.MAX_VALUE - avail)? Integer.MAX_VALUE: n + avail; 
  } 
  /** 
   * Vea el contrato general del <code>mark</code>/código> 
   * método de <código>InputStream</código>. 
   * 
   * @param  readlimit  el límite máximo de bytes que se pueden leer antes 
   *           la posición de marca se vuelve inválida. 
   * @see   java.io.BufferedInputStream#reset() 
   */ 
  public synchronized void mark(int readlimit) { 
    marklimit = readlimit; 
    markpos = pos; 
  } 
  /** 
   * Vea el contrato general del <code>reset</code>/código> 
   * método de <código>InputStream</código>. 
   * <p> 
   * Si <código>markpos</código> es <código>-1</código> 
   * (no se ha establecido marcar o la marcar ha sido 
   * invalidado), una <código>IOException</código> 
   * se lanza. De lo contrario, <código>pos</código> es 
   * igualar a <código>markpos</código>. 
   * 
   * @excepción IOException si este flujo no ha sido marcado o, 
   *         si el marcar ha sido invalidado, o el flujo 
   *         ha sido cerrado invocando su {@link #cerrar()} 
   *         método, o un I/Ocurre un error. 
   * @ver java.io.BufferedInputStream#marcar(int) 
   */ 
  pública synchronized void restablecer() lanza IOException { 
    getBufIfOpen(); // Causar excepción si está cerrado 
    si (markpos < 0) 
      lanzar nueva IOException("Restableciendo a marcar no válida"); 
    pos = markpos; 
  } 
  /** 
   * Prueba si este flujo de entrada admite el <código>marcar</código> 
   * y <código>restablecer</código> métodos. El <código>markSupported</código> 
   * método de <código>BufferedInputStream</código> devuelve 
   * <código>verdadero</código>. 
   * 
   * @devuelve un <código>boolean</código> indica si este tipo de flujo admite 
   *     el <código>marcar</código> y <código>restablecer</código> métodos. 
   * @ver java.io.InputStream#marcar(int) 
   * @see   java.io.InputStream#reset() 
   */ 
  //¿Soporta marcadores? 
  public boolean markSupported() { 
    return true; 
  } 
  /** 
   * Cierra este flujo de entrada y libera cualquier recurso del sistema 
   * asociados con el flujo. 
   * Una vez que se haya cerrado el flujo, se deben llamar a read(), available(), reset(), 
   * o invocaciones de skip() lanzarán IOException. 
   * Cerrar un flujo cerrado anteriormente no tiene efecto. 
   * 
   * @exception IOException si un I/Ocurre un error. 
   */ 
  //Cerrar recursos  
  public void close() throws IOException { 
    byte[] buffer; 
    while ( (buffer = buf) != null) { 
      if (bufUpdater.compareAndSet(this, buffer, null)) { 
        InputStream input = in; 
        in = null; 
        if (input != null) 
          input.close(); 
        return; 
      } 
      // Reintente en caso de que se CASe un nuevo buf en fill() 
    } 
  } 
} 

Gracias por leer, espero que esto les ayude, gracias por su apoyo a nuestro sitio!

Te gustará