java中可通过继承filterinputstream自定义带进度监听的inputstream:在read()各重载方法中统计字节数并回调progresslistener;支持total=-1表示长度未知,需注意线程安全、避免监听器阻塞及close时完成通知。

Java 中没有内置的带进度监听的输入流,但可以通过包装 InputStream 实现:核心是继承 FilterInputStream,在每次 read() 调用中更新已读字节数,并触发回调。
自定义带进度监听的 InputStream
创建一个继承 FilterInputStream 的子类,在构造时接收原始流和进度回调接口:
- 定义回调接口(如
ProgressListener),含onProgress(long bytesRead, long total)方法 - 在
read()的所有重载方法(单字节、字节数组、带 offset/length)中统计读取量 - 每次读取后调用监听器;注意避免在回调中阻塞或抛异常影响流读取
- 若原始流支持
available()或mark()/reset(),需按需委托或明确不支持
处理 totalSize 不确定的情况
网络流或管道流常无法预知总长度。此时可采用两种策略:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 传入
total = -1,监听器收到负值时表示长度未知,只报告当前读取量 - 先尝试通过
URLConnection.getContentLengthLong()或 HTTPContent-Length获取大小;若不可用,再降级为无总量模式 - 也可提供“分段上报”机制,例如每读满 8KB 触发一次回调,避免高频通知
线程安全与资源管理
进度监听本身通常在 I/O 线程中同步执行,需注意:
- 监听器实现应尽量轻量,耗时操作(如 UI 更新)建议切到主线程或使用异步队列
- 不要在监听器中关闭或修改被包装的流,否则可能引发
IOException - 推荐在
close()时调用一次onProgress(bytesRead, total)表示完成,并清空监听器引用防止内存泄漏
简单示例代码片段
以下是最简可用结构(省略异常处理和重载细节):
public class ProgressInputStream extends FilterInputStream {
private final ProgressListener listener;
private final long total;
private long bytesRead;
public interface ProgressListener {
void onProgress(long bytesRead, long total);
}
public ProgressInputStream(InputStream in, long total, ProgressListener listener) {
super(in);
this.total = total;
this.listener = listener;
this.bytesRead = 0;
}
@Override
public int read() throws IOException {
int b = super.read();
if (b != -1) {
bytesRead++;
listener.onProgress(bytesRead, total);
}
return b;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int n = super.read(b, off, len);
if (n > 0) {
bytesRead += n;
listener.onProgress(bytesRead, total);
}
return n;
}
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










