bytearrayoutputstream 是内存中可增长字节数组输出流,用于中短二进制数据临时缓冲;写入后调用 tobytearray() 获取新拷贝数组,reset() 可清空复用,close() 为空实现;大数据量需防性能与 oom 风险。

Java 中用 ByteArrayOutputStream 暂存二进制数据,核心是把它当作一个“内存中的可增长字节数组输出流”——写入的数据不落地、不联网,全存在 JVM 堆内存里,适合中短数据的临时缓冲、拼接或预处理。
基本用法:写入 → 转数组 → 复用或传递
它本质是一个动态扩容的 byte[] 容器,内部维护一个 buf 数组和当前长度 count。每次 write() 都追加到末尾,超出容量时自动扩容(默认增长 50%)。
- 创建后直接调用
write(int)、write(byte[])或write(byte[], int, int)写入数据 - 写完用
toByteArray()获取当前全部内容的**新拷贝数组**(注意:不是引用原 buf,安全但有开销) - 若只需读一次且数据不大,也可用
size()+toByteArray();若需多次读取,建议转成ByteArrayInputStream
避免常见坑:别忘了 close?要不要 reset?
ByteArrayOutputStream 的 close() 是空实现,调不调都行,JVM 不会因此泄漏资源——它不持有文件句柄或 socket。但为代码一致性,可省略。
-
reset() 很有用:清空当前内容(
count = 0),但不释放底层buf内存,适合复用同一个实例多次收集数据(比如循环生成多个小报文) -
慎用 toByteArray() 频繁调用:每次都会新建数组并复制,大数据量时影响性能;如需频繁访问,可考虑先
size()判断,或用buf字段(非 public,需反射——不推荐) -
注意内存占用:buf 容量只增不减,
reset()不缩容;长期复用且数据大小波动大时,可 new 新实例替代
典型场景示例:序列化对象、拼接 HTTP body、压缩前缓存
它常作为中间缓冲,配合其他流使用:
-
序列化对象:
ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(obj); byte[] data = baos.toByteArray(); -
拼接多段二进制:循环调用
baos.write(part1); baos.write(part2); ...,最后统一获取完整数据 -
配合 GZIPOutputStream 压缩:
GZIPOutputStream gos = new GZIPOutputStream(baos); gos.write(raw); gos.close(); byte[] zipped = baos.toByteArray();
替代方案提醒:数据超大时考虑别的办法
如果单次暂存数据经常超过几 MB,或生命周期较长,ByteArrayOutputStream 可能引发 GC 压力或 OOM。此时可考虑:
- 用
ByteBuffer(堆外或直接内存)做更精细控制 - 写入临时文件(
Files.createTempFile),尤其适合超大或需跨线程共享的场景 - 用成熟的内存池库(如 Netty 的
PooledByteBufAllocator)管理缓冲区
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











