一、字节数组流概述
1.1 节点流&包装流
IO流按照处理对象不同来分类,可以分为节点流和包装流。
1)节点流:FileOutputStream、FileInputStream、FileWriter和FileReade
2)包装流:缓冲流、转换流、打印流、数据流和对象流等都属于。
节点流都可以配合包装流来操作,例如:
使用字节流来复制文件效率低,那么我们可以使用缓冲流来提高效率。
使用字节流来存取任意数据类型数据操作繁琐,那么我们可以使用对象流来简化操作等等。
1.2 字节数组流概述
字节数组流,它也属于节点流。
=====================字节数组流分为?================================
1)输入流:ByteArrayInputStream
2) 输出流:ByteArrayOutputStream
=====================小技巧?=======================================
使用字节数组流的时候,为了提高效率和简化操作,可以让字节数组流配合包装流来一起使用。
=====================其余节点流和字节数组流的区别?====================
常见的节点流中,例如:FileInputStream和FileReader都是把“文件”当做数据源,而ByteArrayInputStream则是把内存中的“字节数组”当做数据源。
=====================字节数组流怎样实现的?===========================
字节数组流,就是和内存中的数组相关的一个流,可以将字节数组写到输出流中,也可以将字节数组从输入流中读出来,不涉及磁盘。内存数组输出流可以看成一个可自动扩容的byte数组,可以往里写字节。
=====================字节数组流有什么用?=============================
通过字节数组流,我们可以实现所有数据类型(基本数据类型、引用数据类型)和字节数组之间的转换,然后把转换成字节数组后可以保存到文件或者传输到网络。
二、ByteArrayOutputStream类
ByteArrayOutputStream底层逻辑
ByteArrayOutputStream字节数组输出流在内存中创建一个byte数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。缓冲区初始化时默认32个字节,会随着数据的不断写入而自动增长,但是缓冲区最大容量是2G,只要数据不超过2G,都可以往里写。
数据写出完毕后,可使用toByteArray()方法或toString()方法来获取数据,从而实现了将任意数据类型数据转化为字节数组。
例如,给一个字节数组,然后往这个数组中放入各种数据,比如整形、布尔型、浮点型、字符串和对象等,这种需求就可以使用ByteArrayOutputStream来实现。
【示例】将任意数据类型数据转化为字节数组案例
public class ArrayStreamTest { public static void main(String[] args) { try { // 字节数组输出流(节点流),可将任意数据类型转换为字节数组 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 缓冲流(包装类),用于提高效率 BufferedOutputStream bos = new BufferedOutputStream(baos); // 对象流(包装流),实现写出任意数据类型 ObjectOutputStream oos = new ObjectOutputStream(bos); // 使用对象流来写数据 oos.writeInt(123); oos.writeDouble(123.45); oos.writeChar('A'); oos.writeBoolean(false); oos.writeUTF("node"); oos.writeObject(new Date()); // 刷新流,在获取数据之前一定要先刷新流,因为使用了包装流 oos.flush(); // 获取数据 byte[] bs = baos.toByteArray(); System.out.println(Arrays.toString(bs)); } catch (IOException e) { e.printStackTrace(); } } } |
通过查看底层源码,我们发现ByteArrayOutputStream类的close()方法并没有实现,所以调用close()方法关闭此流后仍可被使用。
三、ByteArrayInputStream
字节数组输入流就是把一个字节数组 byte[] 包装了一下,使其具有流的属性,可顺序读下去,还可标记跳回来继续读,主要的作用就是用来读取字节数组中的数据。
同理,关闭ByteArrayInputStream无效,调用close()方法在关闭此流后仍可被调用。
【示例】读取上个案例获取的字符数组
public class ArrayStreamTest { public static void main(String[] args) { try { // 获取字节数组,返回上个案例中通过字节数组输出流写出的字节数组 byte[] bs = outputStreamMethod(); // 字节数组输入流(节点流),用于读取字节数组中的数据 ByteArrayInputStream bios = new ByteArrayInputStream(bs); // 缓冲流(包装类),用于提高效率 BufferedInputStream bis = new BufferedInputStream(bios); // 对象流(包装流),实现读取指定类型的数据 ObjectInputStream ois = new ObjectInputStream(bis); // 读取数据 System.out.println(ois.readInt()); System.out.println(ois.readDouble()); System.out.println(ois.readChar()); System.out.println(ois.readBoolean()); System.out.println(ois.readUTF()); System.out.println(ois.readObject()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } |
补充,ByteArrayInputStream和ByteArrayOutputStream是字节数组流,那么与之对应的字符数组流则是StringReader和StringWriter。
与字节数组流相比,字符数组流反而用得更少,因为StringBuilder和StringBuffer也能方便的用来存储动态长度的字符,而且大家更熟悉这些类。