2008-10-27 7 views
12

Ich möchte etwas wie eine generische, wiederverwendbare getPosition() Methode, die mir die Anzahl der Bytes vom Startpunkt des Streams gelesen sagen wird. Im Idealfall würde ich es vorziehen, mit allen InputStreams zu arbeiten, so dass ich nicht jeden einzelnen von ihnen einpacken muss, wenn ich sie aus verschiedenen Quellen bekomme.Wie kann ich bei einem Java InputStream den aktuellen Offset im Stream ermitteln?

Gibt es ein solches Biest? Wenn nicht, kann jemand eine vorhandene Implementierung einer Zählung InputStream empfehlen?

Antwort

12

Werfen Sie einen Blick auf CountingInputStream im Commons IO-Paket. Sie haben eine ziemlich gute Sammlung anderer nützlicher InputStream-Varianten.

2

Die Nr. InputStream ist für den Umgang mit potenziell unendlichen Datenmengen gedacht, daher würde ein Zähler im Weg stehen. Zusätzlich dazu, dass Sie alle einpacken, können Sie vielleicht etwas mit Aspekten tun.

19

Sie müssen das in java.io festgelegte Dekorationsmuster befolgen, um dies zu implementieren.

wir es versuchen hier:

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; 
    } 

} 

Die Inputstreams sollen Faden sicher sein, so dass Konten für die liberale Verwendung der Synchronisation. Ich spielte mit volatile und AtomicLong Position Variablen, aber die Synchronisation ist wahrscheinlich am besten, weil es einem Thread erlaubt, auf dem Strom zu operieren und seine Position abzufragen, ohne die Sperre aufzugeben.

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

Dekorierermuster eine schöne Lösung für dieses ist, es stimmen oben. Eine Option wäre, synchronisierte Dokumente zu entfernen und zu dokumentieren, dass die Implementierung nicht Thread-sicher ist. Ein Aufrufer, der read() liest und dann die Position überprüft, muss sich trotzdem synchronisieren, um ein brauchbares (atomares) Verhalten zu erreichen. – volley

+0

Ich glaube nicht, dass irgendjemand von einer bereits existierenden Implementierung weiß? Es scheint, als würde das NIH-Syndrom eine sehr häufige Anforderung neu implementieren. –

+0

Ich mag die Idee und es ist leicht zu einer Anwendung steckbar. Es gibt jedoch ein schwerwiegendes Problem, über das Benutzer dieser Klasse Bescheid wissen sollten: Wenn ein gepufferter Leser diese Klasse verwendet, ist die gemeldete Position falsch, da die Daten in Buckets und nicht Byte für Byte gelesen werden. – Asterios