简介
ByteArrayOutputStream是字节数组输出流,在内存中创建了一个字节数组,所有发送到输出流的数据都会保存到该字节数组的缓冲区中.
1.ByteArrayOutputStream的构造方法:
public ByteArrayOutputStream() {}
public ByteArrayOutputStream(int size) {}
- 第一个构造方法默认创建了一个大小为32的字节数组输出流.
- 第二个构造方法需要传入size,将会创建一个size大小字节数组输出流.
2.内部变量
protected byte buf[];
protected int count;
- buf--用于保存发送到输出流数据的字节数组.
- count--是buf中有效字节数.
3.内部方法
public synchronized void write(int b) {}
public void write(byte b[]) throws IOException
public synchronized void write(byte b[], int off, int len) {}
public synchronized void writeTo(OutputStream out) throws IOException {}
public synchronized void reset() {}
public synchronized byte toByteArray()[] {}
public synchronized int size() {}
public synchronized String toString() {}
public synchronized String toString(String charsetName) {}
public void close() throws IOException {}
- write(int b)--将单个字节b写入到字节输出流的"字节数组"中.
- write(byte b[])--来自超类OutputStream,将整个字节数组b写入到字节输出流的"字节数组"中.
- write(byte b[] ,int off,int len)--将字节数组b,off索引开始,len个字节写入到字节输出流的"字节数组"中.
- writeTo(OutputStream out)--将字节数输出流中的数据写入指定的OutputStream输出流中.
- reset()--将字节输出流中的字节数组count置为0,也就是将现有字节流的数据全部丢弃.
- toByteArray()--创建一个新的字节数组,内容是字节数输出流中的数据.
- size()--返回字节输出流中字节数组大小.
- toString()--使用平台默认的字符集,将输出流中字节数组转换成字符串.
- toString(String charsetName)--使用指定的charsetName字符集,将输出流中的字节数组转换字符串.
- close()--关闭流无效,流已经关闭情况下,调用类中其他方法不会抛出异常.
案例
public class ByteArrayOutputStreamDemo {
public static void main(String[] args) throws IOException {
byte[] bytes = "defghijk".getBytes();
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
// 写入单个字节
byteStream.write(97);
byteStream.write(98);
byteStream.write(99);
System.out.println("-------" + byteStream);
// 写入bytes字节数组,索引0开始,长度5.
byteStream.write(bytes, 0, 5);
System.out.println("-------" + byteStream);
// 计算流中字节数组大小
int size = byteStream.size();
System.out.println("-------size=" + size);
// 将流中的字节数组数据放到一个新字节数组newBytes中
byte[] newBytes = byteStream.toByteArray();
System.out.println("-------" + new String(newBytes));
// 重置,字节输出流中的字节数组count置为0,即清空数据
byteStream.reset();
System.out.println("after reset-------" + byteStream.size());
// 将编码为GBK的字节数组写到字节输出流中.
byte[] encodeBytes = "defghijk".getBytes("GBK");
byteStream.write(encodeBytes);
// toString()默认平台编码(我的GBK),可正常解码.
System.out.println("-------" + byteStream.toString());
// 指定了编码集UTF-16,解码不正常
System.out.println("-------" + byteStream.toString("UTF-16"));
// 将输出流里面的数据写到另外一个字节数组输出流.
ByteArrayOutputStream out = new ByteArrayOutputStream();
byteStream.writeTo(out);
System.out.println(out.toString());
}
}
总结:
(a) 将字节写到字节数组输出流中,方法有三种:一是单个字节写到输出流,使用write(int b),二是字节数组指定的数据写到输出流,使用write(byte b[], int offset,int len),三是整个字节数组的写到输出流,使用write(byte b[]),此方法继承于父类outputStream.
(b) 字节数组---->字节数组输出流(字节数组).字节数组输出流(字节数组)---->字节数组.注意区分两个字节数组,两个过程要采用相同的编码,才能正常解码.测试使用不同的编码集时,得到的前后结果不一致.就上面的实例GBK编码,UTF-8解码,可以正常解码.是因为英文编码在很多编码中位置固定的.具体查看每种编码方法.
源码
public class ByteArrayOutputStream extends OutputStream {
// 保存字节数组输出流数据的字节数组.
protected byte buf[];
// 流中有效字节数
protected int count;
// 无参构造方法,默认创建大小为32字节数组的字节数组输出流.
public ByteArrayOutputStream() {
this(32);
}
// 有参构造方法:创建指定大小的字节数组的字节数组输出流
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: " + size);
}
buf = new byte[size];
}
// 要扩容大小只有大于buf.length情况下才进行扩容
private void ensureCapacity(int minCapacity) {
// overflow-conscious code
if (minCapacity - buf.length > 0)
grow(minCapacity);
}
// 增加容量
private void grow(int minCapacity) {
// 旧容量是buf.length,新容量的大小是旧容量的2倍
int oldCapacity = buf.length;
int newCapacity = oldCapacity << 1;
// 新容量和要扩充的容量里面取较大值
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity < 0) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
buf = Arrays.copyOf(buf, newCapacity);
}
// 将一个字节写到字节数组输出流中
public synchronized void write(int b) {
// 容量增加1,count索引位置的数据是b
ensureCapacity(count + 1);
buf[count] = (byte) b;
count += 1;
}
// 将字节数组b写到字节数组输出流中,off是b中起始位置,len是写入长度
public synchronized void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) - b.length > 0)) {
throw new IndexOutOfBoundsException();
}
// 现有容量上面扩容,大小为len
ensureCapacity(count + len);
System.arraycopy(b, off, buf, count, len);
// 有效字节数大小加len
count += len;
}
// 将字节数组输出流中的数据写到out输出流中
public synchronized void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}
// 重置字节数组输出流的count,即将流中数据置为空
public synchronized void reset() {
count = 0;
}
// 将字节数组输出流中数据复制到一个新字节数组中
public synchronized byte toByteArray()[] {
return Arrays.copyOf(buf, count);
}
// 返回字节数组输出流中有效字节数
public synchronized int size() {
return count;
}
// 按照平台默认编码集解码成字符串
public synchronized String toString() {
return new String(buf, 0, count);
}
// 将字节数组里面的数组按照指定编码charsetName解码成字符串
public synchronized String toString(String charsetName) throws UnsupportedEncodingException {
return new String(buf, 0, count, charsetName);
}
@Deprecated
public synchronized String toString(int hibyte) {
return new String(buf, hibyte, 0, count);
}
// 流已经关闭情况下,调用其他方法不会抛出异常
public void close() throws IOException {}
}
源码总结:
(a)字节数组输出流ByteArrayOutoutStream,里面内容就是字节数组,也就是说所有写入到字节数组输出流中的数据全部保存到字节数组里面了.
(b)可以创建默认32大小和指定大小字节数组输出流,从源码可以看出.字节数组输出流中没有写到文件的方法.但可以将数据写到其他输出流或者是字节数组中.