- JAVA IO将流分为两类:节点流和处理流(过滤流)
- 节点流也称为低级流,特点:是实际连接程序与另一端的流,负责实际读写字节数据的流,读写一定是建立在节点流基础上进行的!
- 处理流也称为高级流,特点:不能独立存在,必须连接在其他流上,目的是当数据经过当前流时对其进行操作简化我们的读写。
- 实际开发中我们经常串联一组高级流最终到某个低级流上,读写数据可以以流水线式的加工处理完成复杂的读写,这个过程称为"流的连接"。
- 文件流就是典型的低级流,是实际连接程序与文件的流,负责读写文件数据
java.io.BufferedInputStream 构造器缓冲流是一对高级流,在流链接中链接它的目的是加快读写效率。缓冲流内部默认缓冲区为8kb,缓冲流总是块读写数据来提高读写效率。
常用方法BufferedOutputStream(OutputStream out):创建一个默认8kb大小缓冲区的缓冲字节输出流,并连接到参数指定的字节输出流上。
BufferedOutputStream(OutputStream out,int size):创建一个size指定大小(单位是字节)缓冲区的缓冲字节输出流,并连接到参数指定的字节输出流上。
BufferedOutputStream 构造器flush():强制将缓冲区中已经缓存的数据一次性写出
缓冲流的写出方法功能与OutputStream上一致,需要知道的时write方法调用后并非实际写出,
而是先将数据存入缓冲区(内部的字节数组中),当缓冲区满了时会自动写出一次。
常用方法BufferedInputStream(InputStream in):创建一个默认8kb大小缓冲区的缓冲字节输入流,并连接到参数指定的字节输入流上。
BufferedInputStream(InputStream in,int size):创建一个size指定大小(单位是字节)缓冲区的缓冲字节输入流,并连接到参数指定的字节输入流上。
缓冲字节输入流的read方法第一次去调用是会一次次那个块读一组数据进入内部的缓冲区,然后返回其中第一个字节。
第二次调用时会直接将数组中第二个字节返回,直到所有字节均返回,下次调用read方法会再次块读数据进入数组。
因此缓冲流本质就是将我们的读写操作统一转换为块读写形式来保证读写效率
public class CopyDemo3 {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("周杰伦-晴天.flac");
FileOutputStream fos=new FileOutputStream("周杰伦-晴天_cp.flac");
BufferedInputStream bis=new BufferedInputStream(fis,1024*10);
BufferedOutputStream bos=new BufferedOutputStream(fos,1024*10);
long start=System.currentTimeMillis();
int d;
while ((d=bis.read())!=-1){
bos.write(d);
}
System.out.println();
long end=System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
bis.close();
bos.close();
}
}
4.缓冲输出流写出数据时的缓冲区问题
通过缓冲流写出的数据会被临时存入缓冲流内部的字节数组,直到数组数据存满,数据才会真实写出一次
缓冲流的flush方法在于强制将缓冲区中已经缓存的数据一次性写出
注:该方法实际上是在字节输出流的超类OutStream上定义的,并非只有缓冲输出流有这个方法。但是实际上只有缓冲输出流的该方法有实际意义,其他的实现该方法的目的仅仅是为了在流连接过程中传递flush动作给缓冲输出流。
public class BOSDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos=new FileOutputStream("bos.txt");
BufferedOutputStream bos=new BufferedOutputStream(fos);
String line="天青色等烟雨,而我在等你";
byte[] data = line.getBytes(StandardCharsets.UTF_8);
bos.write(data);
bos.flush();
System.out.println("书写完毕");
}
}
5.对象流
- java.io.ObjectInputStream和ObjectOutputStream
- 对象流的功能:进行对象序列化与反序列化
- 对象序列化由对象输出流完成:将一个java对象按照其结构转换为一组字节的过程
- 对象反序列化由对象输入流完成:将一组字节还原为一个java对象的过程
需要进行序列化的类必须实现接口:java.io.Serializable实现序列化接口最好主动定义版本号这个常量。
这样一来对象序列化时就不会根据类的结构生成一个版本号,而是使用该固定值。
那么反序列化时,只要还原的对象和当前类的版本号一致就可以还原。
transient关键字可以修饰属性,用于在进行对象序列化时忽略不必要的属性,达到对象瘦身的目的
- 如果序列化的对象没有实现可序列化接口:java.io.Serializable就会抛出异常:java.io.NotSerializableException
- 该接口没有任何抽象方法。但是只有实现了该接口的类的实例才能进行序列化与反序列化
- 实现了序列化接口的类建议显示的定义常量:static final long serialVersionUID = 1L;
//文件输出流(低级流):将字节写入指定文件中
FileOutputStream fos = new FileOutputStream("person.obj");
//对象输出流(高级流):将一个java对象进行序列化
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
//反序列化过程
FileInputStream fis=new FileInputStream("person.obj");
ObjectInputStream ois=new ObjectInputStream(fis);
Object obj = ois.readObject();
Person person=(Person) obj;
System.out.println(person);
ois.close();



