2008-10-27 12 views
12

Me gustaría algo así como un método getPosition() genérico, reutilizable que me dirá la cantidad de bytes leídos desde el punto de inicio de la transmisión. Idealmente, preferiría que esto funcione con todos los InputStreams, de modo que no tenga que envolver todos y cada uno de ellos, ya que los obtengo de fuentes dispares.Dado un Java InputStream, ¿cómo puedo determinar el desplazamiento actual en la secuencia?

¿Existe tal bestia? Si no, ¿alguien puede recomendar una implementación existente de un conteo InputStream?

Respuesta

12

Eche un vistazo a CountingInputStream en el paquete Commons IO. También tienen una buena colección de otras variantes útiles de InputStream.

2

El número InputStream está diseñado para manejar cantidades de datos potencialmente infinitas, por lo que un contador se interpondrá en el camino. Además de envolverlos a todos, es posible que puedas hacer algo con aspectos.

19

Deberá seguir el patrón Decorator establecido en java.io para implementar esto.

Vamos a darle una oportunidad aquí:

import java.io.FilterInputStream; 
import java.io.IOException; 
import java.io.InputStream; 

public final class PositionInputStream 
    extends FilterInputStream 
{ 

    private long pos = 0; 

    private long mark = 0; 

    public PositionInputStream(InputStream in) 
    { 
    super(in); 
    } 

    /** 
    * <p>Get the stream position.</p> 
    * 
    * <p>Eventually, the position will roll over to a negative number. 
    * Reading 1 Tb per second, this would occur after approximately three 
    * months. Applications should account for this possibility in their 
    * design.</p> 
    * 
    * @return the current stream position. 
    */ 
    public synchronized long getPosition() 
    { 
    return pos; 
    } 

    @Override 
    public synchronized int read() 
    throws IOException 
    { 
    int b = super.read(); 
    if (b >= 0) 
     pos += 1; 
    return b; 
    } 

    @Override 
    public synchronized int read(byte[] b, int off, int len) 
    throws IOException 
    { 
    int n = super.read(b, off, len); 
    if (n > 0) 
     pos += n; 
    return n; 
    } 

    @Override 
    public synchronized long skip(long skip) 
    throws IOException 
    { 
    long n = super.skip(skip); 
    if (n > 0) 
     pos += n; 
    return n; 
    } 

    @Override 
    public synchronized void mark(int readlimit) 
    { 
    super.mark(readlimit); 
    mark = pos; 
    } 

    @Override 
    public synchronized void reset() 
    throws IOException 
    { 
    /* A call to reset can still succeed if mark is not supported, but the 
    * resulting stream position is undefined, so it's not allowed here. */ 
    if (!markSupported()) 
     throw new IOException("Mark not supported."); 
    super.reset(); 
    pos = mark; 
    } 

} 

Los InputStreams pretenden ser seguro para subprocesos, por lo que las cuentas para el uso liberal de sincronización. Jugué con las variables de posición volatile y AtomicLong, pero la sincronización es probablemente la mejor porque permite que un hilo funcione en el flujo y consulte su posición sin renunciar al bloqueo.

PositionInputStream is = … 
synchronized (is) { 
    is.read(buf); 
    pos = is.getPosition(); 
} 
+0

Decorator es una buena solución para éste, la votación para arriba. Una opción sería eliminar sincronizados y documentar que la implementación no es segura para subprocesos. Una persona que llama que lee() y luego verifica la posición tiene que sincronizarse de todos modos para lograr un comportamiento utilizable (atómico). – volley

+0

Supongo que nadie sabe de una implementación de esto ya existente? Parece que el síndrome NIH debe volver a implementar lo que debe ser un requisito muy común. –

+0

Me gusta la idea y se puede conectar fácilmente a una aplicación. Sin embargo, hay un problema grave que los usuarios de esta clase deberían saber: si un lector almacenado utiliza esta clase, la posición informada es falsa, ya que los datos se leen en intervalos y no en bytes por bytes. – Asterios

Cuestiones relacionadas