/* * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2016 Maxence Bernard * * muCommander is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * muCommander is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.mucommander.commons.io; import java.io.IOException; import java.io.InputStream; /** * An InputStream that keeps track of the number of bytes that have been read from it. Bytes that are skipped (using * {@link #skip(long)} are by default accounted for, {@link #setCountSkippedBytes(boolean)} can be used to change this. * * <p>The actual number of bytes can be retrieved from the {@link ByteCounter} instance returned by {@link #getCounter()}. * The {@link #CounterInputStream(InputStream, ByteCounter)} constructor can be used to specify an existing * ByteCounter instance instead of creating a new one. The ByteCounter will always remain accessible, even * after this stream has been closed. * * @see ByteCounter * @author Maxence Bernard */ public class CounterInputStream extends InputStream { /** Underlying InputStream */ private final InputStream in; /** Byte counter */ private final ByteCounter counter; /** Should skipped bytes be accounted for ? (enabled by default) */ private boolean countSkippedBytes = true; /** * Creates a new CounterInputStream using the specified InputStream. A new {@link ByteCounter} will be created. * * @param in the underlying InputStream the data will be read from */ public CounterInputStream(InputStream in) { this.in = in; this.counter = new ByteCounter(); } /** * Creates a new CounterInputStream using the specified InputStream and {@link ByteCounter}. * The provided <code>ByteCounter</code> will NOT be reset, whatever value it contains will be kept. * * @param in the underlying InputStream the data will be read from */ public CounterInputStream(InputStream in, ByteCounter counter) { this.in = in; this.counter = counter; } /** * Returns the ByteCounter that holds the number of bytes that have been read (and optionally skipped) from this * InputStream. */ public ByteCounter getCounter() { return this.counter; } /** * Specifies whether or not skipped bytes (using {@link #skip(long)} should be accounted for. * This is by default enabled, bytes that are skipped are added to the ByteCounter. * * @param countSkippedBytes if true, skipped bytes will be accounted for, the ByteCounter will be increased * by the number of skipped bytes */ public void setCountSkippedBytes(boolean countSkippedBytes) { this.countSkippedBytes = countSkippedBytes; } /** * Returns true if skipped bytes (using {@link #skip(long)} are accounted for. * This is by default enabled, bytes that are skipped are added to the ByteCounter. */ public boolean getCountSkippedBytes() { return countSkippedBytes; } //////////////////////////////// // InputStream implementation // //////////////////////////////// @Override public int read() throws IOException { int i = in.read(); if(i>0) counter.add(1); return i; } @Override public int read(byte b[]) throws IOException { int nbRead = in.read(b); if(nbRead>0) counter.add(nbRead); return nbRead; } @Override public int read(byte b[], int off, int len) throws IOException { int nbRead = in.read(b, off, len); if(nbRead>0) counter.add(nbRead); return nbRead; } @Override public long skip(long n) throws IOException { long nbSkipped = in.skip(n); // Count skipped bytes only if this has been enabled if(countSkippedBytes && nbSkipped>0) counter.add(nbSkipped); return nbSkipped; } @Override public int available() throws IOException { return in.available(); } @Override public void close() throws IOException { in.close(); } @Override public void mark(int readLimit) { in.mark(readLimit); } @Override public boolean markSupported() { return in.markSupported(); } @Override public void reset() throws IOException { in.reset(); } }