Dado um Java InputStream, como posso determinar o deslocamento atual no fluxo?
-
04-07-2019 - |
Pergunta
Eu gostaria de algo como um genérico, reutilizável getPosition()
Método que me dirá o número de bytes lidos no ponto de partida do fluxo. Idealmente, eu preferiria que isso funcione com todos os fluxos de entrada, para não precisar embrulhar cada um deles, pois os obtém de fontes díspares.
Esse animal existe? Caso contrário, alguém pode recomendar uma implementação existente de uma contagem InputStream
?
Solução
Dar uma olhada em ContingInputStream no pacote do Commons. Eles também têm uma boa coleção de outras variantes de entrada úteis.
Outras dicas
Você precisará seguir o padrão de decorador estabelecido em java.io
Para implementar isso.
Vamos tentar aqui:
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;
}
}
Os InsputStreams devem ser seguros, de modo que expliquem o uso liberal da sincronização. Eu brinquei com volatile
e AtomicLong
Posicionar variáveis, mas a sincronização é provavelmente melhor porque permite que um thread opere no fluxo e consulte sua posição sem renunciar à trava.
PositionInputStream is = …
synchronized (is) {
is.read(buf);
pos = is.getPosition();
}
Não. InputStream
destina -se a lidar com quantidades potencialmente infinitas de dados, portanto, um contador atrapalharia. Além de envolver todos eles, você poderá fazer algo com aspectos.
Há também CountingInputStream
dentro Goiaba.
Apidocs:https://google.github.io/guava/releases/19.0/api/docs/com/google/common/io/cinginputstream.html
Fonte: https://github.com/google/guava/blob/master/guava/src/com/google/common/io/cinginputstream.java