java – 用于进度报告的InputStream或Reader包装器

所以,我正在将文件数据提供给带有Reader的API,我想要一种报告进度的方法.

看起来应该直截了当地编写一个包装FileInputStream的FilterInputStream实现,跟踪读取的字节数与总文件大小,并触发一些事件(或调用一些update()方法)来报告小数进度.

(或者,它可以报告绝对字节读取,而其他人可以进行数学计算 – 在其他流式传输情况下可能更常用.)

我知道我以前见过这个,我甚至可能以前做过,但我找不到代码,而且我很懒.有没有人得到它?或者有人可以提出更好的方法吗?

一年(有点)之后……

我在下面根据Adamski的答案实施了一个解决方案,并且它有效,但经过几个月的使用后我不推荐它.当您有大量更新时,解雇/处理不必要的进度事件会产生巨大的成本.基本的计数机制很好,但是对于那些关心进度调查的人来说要好得多,而不是把它推到他们身上.

(如果你知道总的大小,你可以尝试每次> 1%的变化或者其他任何事情来触发一个事件,但它确实不值得这么麻烦.通常,你没有.)

解决方法:

这是一个相当基本的实现,在读取其他字节时触发PropertyChangeEvents.一些警告:

>该类不支持标记或重置操作,尽管这些操作很容易添加.
>该类不检查读取的总字节数是否超过预期的最大字节数,尽管在显示进度时总是可以通过客户端代码处理.
>我没有测试代码.

码:

public class ProgressInputStream extends FilterInputStream {
    private final PropertyChangeSupport propertyChangeSupport;
    private final long maxNumBytes;
    private volatile long totalNumBytesRead;

    public ProgressInputStream(InputStream in, long maxNumBytes) {
        super(in);
        this.propertyChangeSupport = new PropertyChangeSupport(this);
        this.maxNumBytes = maxNumBytes;
    }

    public long getMaxNumBytes() {
        return maxNumBytes;
    }

    public long getTotalNumBytesRead() {
        return totalNumBytesRead;
    }

    public void addPropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }

    public void removePropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }

    @Override
    public int read() throws IOException {
        int b = super.read();
        updateProgress(1);
        return b;
    }

    @Override
    public int read(byte[] b) throws IOException {
        return (int)updateProgress(super.read(b));
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        return (int)updateProgress(super.read(b, off, len));
    }

    @Override
    public long skip(long n) throws IOException {
        return updateProgress(super.skip(n));
    }

    @Override
    public void mark(int readlimit) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void reset() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean markSupported() {
        return false;
    }

    private long updateProgress(long numBytesRead) {
        if (numBytesRead > 0) {
            long oldTotalNumBytesRead = this.totalNumBytesRead;
            this.totalNumBytesRead += numBytesRead;
            propertyChangeSupport.firePropertyChange("totalNumBytesRead", oldTotalNumBytesRead, this.totalNumBytesRead);
        }

        return numBytesRead;
    }
}
上一篇:java – 使一个InputStream不止一次读取,而不管markSupported()


下一篇:使用java来修改文件内容