Этот ответ повторяет предыдущие 1 | 2 на основе BufferInputStream
. Основные изменения в том, что это позволяет бесконечное повторное использование. И заботится о закрытии исходного входного потока для освобождения системных ресурсов. Ваша ОС определяет их ограничение, и вы не хотите, чтобы в программе не было файловых дескрипторов (). Именно поэтому вам всегда следует «потреблять» ответы, например, с помощью apache EntityUtils.consumeQuietly()
). EDIT Обновлен код для обработки для готовых потребителей, которые используют read(buffer, offset, length)
, в этом случае может случиться, что BufferedInputStream
изо всех сил пытается посмотреть на источник, этот код защищает от такого использования.
public class CachingInputStream extends BufferedInputStream {
public CachingInputStream(InputStream source) {
super(new PostCloseProtection(source));
super.mark(Integer.MAX_VALUE);
}
@Override
public synchronized void close() throws IOException {
if (!((PostCloseProtection) in).decoratedClosed) {
in.close();
}
super.reset();
}
private static class PostCloseProtection extends InputStream {
private volatile boolean decoratedClosed = false;
private final InputStream source;
public PostCloseProtection(InputStream source) {
this.source = source;
}
@Override
public int read() throws IOException {
return decoratedClosed ? -1 : source.read();
}
@Override
public int read(byte[] b) throws IOException {
return decoratedClosed ? -1 : source.read(b);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return decoratedClosed ? -1 : source.read(b, off, len);
}
@Override
public long skip(long n) throws IOException {
return decoratedClosed ? 0 : source.skip(n);
}
@Override
public int available() throws IOException {
return source.available();
}
@Override
public void close() throws IOException {
decoratedClosed = true;
source.close();
}
@Override
public void mark(int readLimit) {
source.mark(readLimit);
}
@Override
public void reset() throws IOException {
source.reset();
}
@Override
public boolean markSupported() {
return source.markSupported();
}
}
}
Чтобы повторно использовать его, просто сначала закройте его, если это не так.
Однако существует одно ограничение: если поток закрыт до того, как будет прочитано все содержимое исходного потока, то у этого декоратора будут неполные данные, поэтому убедитесь, что весь поток прочитан перед закрытием.