Java基础IO流介绍之三——什么是字节过滤流、常用的字节过滤流有哪些
字节流的过滤流
作用:为节点流增强功能的
1、字节流的缓冲流(BufferedXXX)
1、概述
缓冲: 就是一个字节数组
实现高效的原理: 本质就是减少对硬盘的访问次数
2、构造方法
方法名 | 说明 |
---|---|
BufferedOutputStream(OutputStream out) | 创建字节缓冲输出流对象 |
BufferedInputStream(InputStream in) | 创建字节缓冲输入流对象 |
3、高效原理(减少对硬盘的访问的次数)
BufferedOutputStream高效的原理:在该类型中准备了一个数组,存储字节信息.
当外界调用write方法想写出一个字节的时候,该对象直接将这个字节存储到了自己的数组中,而不刷新到文件中。
一直到该数组所有8192个位置全都占满,该对象才把这个数组中的所有数据一次性写出到目标文件中。
如果最后一次循环过程中,没有将数组写满,最终在关闭流对象的时候,也会将该数组中的数据刷新到文件中。
BufferedInputStream高效的原理:在该类型中准备了一个数组,存储字节信息.
当外界调用read()方法想获取一个字节的时候,该对象从文件中一次性读取了8192个字节到数组中,只返回了第一个字节给调用者。
将来调用者再次调用read方法时,当前对象就不需要再次访问磁盘,只需要从数组中取出一个字节返回给调用者即可.
由于读取的是数组,所以速度非常快。
当8192个字节全都读取完成之后,再需要读取一个字节,就得让该对象到文件中读取下一个8192个字节了。
4、关于关流和刷新流的区别
在调用 close() 方法关流的时候,在关闭之前会先进行刷新的操作,但是关流之后此流对象就不可以再使用了.
刷新 flush() 在调用的时候,会将缓冲区的数据刷新到硬盘中, 调用之后,并不会使流对象关闭 后边还可以继续使用.在开发中还是建议 先刷新 在关流 .
5、关于过滤流中是否需要关闭节点流
只需要在代码中将过滤流关闭即可,关闭了过滤流其实已经关闭了节点流.
案例
//案例1:
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
public class Demo3 {
public static void main(String[] args) throws Exception{
//创建一个File对象
File file = new File("file/a.txt");
// 创建 文件字节输出流 ----> 节点流 ----> 凉水
FileOutputStream fileOutputStream = new FileOutputStream(file);
//通过节点流对象 创建过滤流 增强功能
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
//使用 过滤流 进行数据的处理
String s = "abcd";
//fileOutputStream.write(s.getBytes());//不关闭流 直接写入
bufferedOutputStream.write(s.getBytes());//首先写入到了 缓冲区(内存里) 还没有写入硬盘
//刷新
//bufferedOutputStream.flush();
//关流
bufferedOutputStream.close();
fileOutputStream.close();
}
}
//案例2:
import java.io.*;
public class Demo3 {
public static void main(String[] args) throws Exception{
//创建一个File对象
File file = new File("file/a.txt");
//创建 节点流
FileInputStream fileInputStream = new FileInputStream(file);
// 通过节点流 创建 过滤流的对象
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
//使用 过滤流 处理 数据
int read = bufferedInputStream.read();//读取一个字节 其实是读取了一个字节数组长度的数据 但是只返回第一个字节
System.out.println((char)read);
int read1 = bufferedInputStream.read();//读取的第二个字节数据 直接从上边的缓冲区数组中 返回第二个字节
System.out.println((char)read1);
//关流
bufferedInputStream.close();
}
}
2、PrintStream流
1、概述
PrintStream介绍:
是OutputStream子类,是字节流
打印数组时,如果是字符数组,可以直接显示数组内容,是因为调用print(char[] ch)或println(char[] ch)
打印其他数组时,调用的是print(Object obj)或println(Object obj),因此打印的是数组地址值。
2、构造方法
方法名 | 说明 |
---|---|
PrintStream(File file) | 创建具有指定文件且不带自动行刷新的新打印流。 |
PrintStream(OutputStream out) | 创建新的打印流。 |
PrintStream(String fileName) | 创建具有指定文件名称且不带自动行刷新的新打印流。 |
案例
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class Demo4 {
public static void main(String[] args) throws FileNotFoundException {
//构造方法
// File file= new File("file/a.txt");
// PrintStream stream1 = new PrintStream(file);
//
// FileOutputStream fileOutputStream = new FileOutputStream(file);
// PrintStream stream2 = new PrintStream(fileOutputStream);
PrintStream stream3 = new PrintStream("file/a.txt");
//具有很多重载的 print方法
// stream3.println(23);
// stream3.println('a');
// stream3.println(12.3);
// stream3.println("abcdefg");
//创建一个学生对象
// Student s = new Student("刘洋",13);
// stream3.println(s);//可以将 对象 toString方法生成的字符串直接输出到文件中 对象的属性信息
char[] chars = "adfsfsafdsafd".toCharArray();
System.out.println(chars.toString());
stream3.println(chars);
//关流
stream3.flush();
stream3.close();
}
}
class Student{
String name;
int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3、对象流
1、概述
ObjectOutputStream / ObjectInputStream 对象输入输出流
2、作用
可以实现对象的序列化和反序列化
序列化: 将内存中的对象数据写入到持久化存储设备中的过程 叫做对象的序列化.
反序列化: 将持久化存储设备中的对象数据读入到内存中的过程 叫做对象的反序列化.
3、构造方法
ObjectInputStream(InputStream in)
创建从指定的InputStream读取的ObjectInputStream。
ObjectOutputStream(OutputStream out)
创建一个写入指定的OutputStream的ObjectOutputStream。
4、常用方法
void writeObject(Object obj)
将指定的对象写入ObjectOutputStream。
int read()
读取一个字节的数据。
Object readObject()
从ObjectInputStream读取一个对象。
//案例1:
import java.io.*;
public class Demo5 {
public static void main(String[] args) throws Exception{
File file = new File("file/d.txt");//二进制的文件
// FileOutputStream fileOutputStream = new FileOutputStream(file);//节点流
//
// ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//
// //功能增强了
// int a = 8;
// objectOutputStream.write(a);
// objectOutputStream.close();
// System.out.println("写入完毕");
//读取 数据8
// FileInputStream fileInputStream = new FileInputStream(file);
// ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
// int i = objectInputStream.read();
// i++;
// System.out.println(i);
// objectInputStream.close();
}
}
//案例2:
import java.awt.datatransfer.FlavorEvent;
import java.io.*;
public class Demo6 {
public static void main(String[] args) throws Exception{
//创建一个对象
Student student = new Student("李程",38);
//实现序列化
File file = new File("file/a.txt");
//
// FileOutputStream fileOutputStream = new FileOutputStream(file);//节点流
//
// ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//
// //写对象了
// objectOutputStream.writeObject(student);
//
// //关流
// objectOutputStream.close();
FileInputStream fileInputStream = new FileInputStream(file);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Object o = objectInputStream.readObject();
//向下转型
Student s1 = (Student) o;
s1.name = "刘能";
System.out.println(o);
}
}
//案例3:
import java.io.*;
public class Demo7 {
public static void main(String[] args) throws Exception{
File file = new File("file/a.txt");
// FileOutputStream fileOutputStream = new FileOutputStream(file);
//
// //创建对象流
// ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//
// //创建一个对象
// Student s1 = new Student("李程",12);
//
// objectOutputStream.writeObject(s1);
//
// //关流
// objectOutputStream.close();
// System.out.println("序列化完毕");
//反序列化
FileInputStream fileInputStream = new FileInputStream(file);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Object o = objectInputStream.readObject();
System.out.println(o);
System.out.println("反序列化结束");
}
}
5、注意事项
1. 实现对象序列化,必须要求这个对象所属的类实现 Serializable 接口
2. 如果一个对象中的某个属性的值不想被序列化,这个属性需要使用transient 修饰
3. serialVersionUID:可以为序列化指定版本id.防止类修改后读取数据的异常.
格式为: private static final long serialVersionUID = 42L;
4.当一个自定义对象实现序列化时此时在类中存在自定义类类型的属性时,属性也要实现序列化接口.