Java学习之路(五十七)| IO流(四)节点流和处理流

各自努力,最高处见!加油!

一、节点流和处理流

在这里插入图片描述

  1. 节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter。
  2. 处理流(也叫包装流)是链接已存在的流(节点流或处理流)之上,为程序提供更强大的读写功能,如:BufferedReader、BufferedWriter。
    在这里插入图片描述BufferedReader类中,有属性Reader,即可以封装一个节点流,该节点流可以是任意的,只要是Reader子类。

二、节点流和处理流的区别和联系

  1. 节点流是底层流,直接跟数据源相接。
  2. 处理流(包装流)包装节点流,既可以消除不同节点流的现实差异(对文件操作,对管道操作,对数组操作),也可以提供更方便的方法来完成输入输出。
  3. 处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连。

处理流的功能主要体现在以下两个方面:

  1. 性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
  2. 操作的便捷:处理流可能提供一系列便捷的方法来一次输入输出大批量数据,使用更加灵活方便。

三、BufferedReader和BufferedWriter

  • BufferedReader和BufferedWriter属于字符流,是按照字符来读取数据的(尽量不要用来读二进制文件)。关闭处理流的时候,只需要关闭外层流即可。

BufferedReader示例代码:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReader_ {
    public static void main(String[] args) throws IOException {
        String filePath="D:\\Java_code\\LearnPlus\\news2.txt";

        BufferedReader bufferedReader=new BufferedReader(new FileReader(filePath));
        String line;
//        line=bufferedReader.readLine();//到达流的末尾,返回空
        while ((line=bufferedReader.readLine())!=null){
            System.out.println(line);
        }

        bufferedReader.close();//只关闭处理流就行,底层源码会自动关闭节点流。
    }
}

BufferedWriter示例代码:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath="D:\\Java_code\\LearnPlus\\news3.txt";

        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
        //BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));//表示以追加的方式写入,在原来文件的基础上写入内容,相当于本次操作的光标位于文件最末端。
        bufferedWriter.write("helloWorld");
        bufferedWriter.newLine();//插入一个和系统相关的换行
        bufferedWriter.write("helloworld");

        bufferedWriter.close();
    }
}

使用BufferedReader和BufferedWriter完成文本拷贝
注意:BufferedReader和BufferedWriter是安装字符操作,不要去操作二进制文件【声音、视频、doc、PDF等等】,可能造成文件损坏。

示例代码:

import java.io.*;

public class BufferedCopy {
    public static void main(String[] args)  {
        String srcFilePath="D:\\Java_code\\LearnPlus\\news2.txt";
        String dstFilePath="D:\\Java_code\\LearnPlus\\news3.txt";

        BufferedReader bufferedReader=null;
        BufferedWriter bufferedWriter=null;
        String line;

        try {
            bufferedReader=new BufferedReader(new FileReader(srcFilePath));
            bufferedWriter=new BufferedWriter(new FileWriter(dstFilePath));

            while ((line=bufferedReader.readLine())!=null){
                bufferedWriter.write(line);
                bufferedWriter.write("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bufferedReader.close();
                bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("拷贝完毕!");
        }
    }
}

四、BufferedInputStream和BufferedOutputStream

在这里插入图片描述
在这里插入图片描述

  • BufferedInputStream是字节流,在创建BufferedInputStream时会创建一个内部缓冲数组。
    在这里插入图片描述
  • BufferedOutputStream是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统。

在这里插入图片描述

示例代码:使用BufferedInputStream和BufferedOutputStream拷贝视频文件

import java.io.*;

public class BufferedInputStream_ {
    public static void main(String[] args) {
        String srcFilePath="D:\\桌面\\lzm1.mp4";
        String dstFilePath="D:\\Java_code\\LearnPlus\\lzm.mp4";
        BufferedOutputStream bufferedOutputStream=null;
        BufferedInputStream bufferedInputStream=null;
        byte[] buff=new byte[1024];//字节读取都是用byte读取
        int len;

        try {
            bufferedInputStream=new BufferedInputStream(new FileInputStream(srcFilePath));
            bufferedOutputStream=new BufferedOutputStream(new FileOutputStream(dstFilePath));

            while ((len=bufferedInputStream.read(buff))!=-1){
                bufferedOutputStream.write(buff,0,len);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bufferedInputStream.close();
                bufferedOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

五、对象流ObjectInputStream和ObjectOutputStream

先看开发中的要求:

  1. 将int num=100这个int数据保存到文件中,注意不是100这个数据,而是int 100 。并且,能够从文件中直接恢复int 100。
  2. 将Dog dog=new Dog90(“小黄”,3)这个dog对象保存到文件中,并且能够从文件恢复。
  3. 上面的要求,就是能够将基本数据类型或者对象进行序列化反序列化操作。

序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的值数据类型
  2. 反序列化就是在恢复数据时,恢复数据的值数据类型
  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的。
  4. 为了让某个类是可序列化的,该类必须实现如下两个接口之一:
    A、Serializable//这是一个标记接口:一个空接口,没有任何方法。
    B、Exernalizable//继承了Serializable,并且有方法要实现。
  5. ObjectOutputStream提供序列化功能,ObjectInputStream提供反序列化功能。

类图

在这里插入图片描述
在这里插入图片描述

示例代码:

序列化输出代码

/**
序列化输出代码
*/
import ObjectInputStreamAndObjectOutputStream.Dog;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutStream_ {
    public static void main(String[] args) {
        //序列化后,保存的文件格式,不是存文本,而是按照他的格式来存。
        String filePath="D:\\Java_code\\LearnPlus\\data.txt";
        ObjectOutputStream objectOutputStream =null;

        try {
            objectOutputStream=new ObjectOutputStream(new FileOutputStream(filePath));
            objectOutputStream.writeInt(100);//int -->Integer(Serializable)
            objectOutputStream.writeBoolean(true);
            objectOutputStream.writeChar('a');
            objectOutputStream.writeDouble(9.5);
            objectOutputStream.writeUTF("helloWorld");//字符串

            objectOutputStream.writeObject(new Dog("老黄",5));//要想实现序列化接口,必须实现接口。

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                objectOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

反序列化读入代码

/**
反序列化读入代码
*/
import ObjectInputStreamAndObjectOutputStream.Dog;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ObjectInputStream_ {
    public static void main(String[] args) {
        String  filePath="D:\\Java_code\\LearnPlus\\data.txt";
        ObjectInputStream objectInputStream=null;
        Object o=null;

        try {
            objectInputStream=new ObjectInputStream(new FileInputStream(filePath));

            System.out.println(objectInputStream.readInt());
            System.out.println(objectInputStream.readBoolean());
            System.out.println(objectInputStream.readChar());
            System.out.println(objectInputStream.readDouble());
            System.out.println(objectInputStream.readUTF());

            try {
                o=objectInputStream.readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            System.out.println("运行类型:"+o.getClass());//底层Object-->Dog
            System.out.println("dog信息:"+o);
            //读取对象的信息可以不需要知道Dog类的详细信息,但是想要向下转型的话必须要导入Dog类的本体
            Dog dog=(Dog)o;
            System.out.println(dog.getName());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                objectInputStream.close();//关闭流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        System.out.println("程序执行完毕");
    }
}

对象实体,要声明为public,让序列化程序和反序列化程序都能读到该类

/**
对象实体,要声明为public,让序列化程序和反序列化程序都能读到该类
*/
import java.io.Serializable;

public class Dog implements Serializable {
    private String name;
    private int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在这里插入图片描述

本例需注意:读取对象的信息可以不需要知道Dog类的详细信息,但是想要向下转型的话必须要类的本体。由图中序列化后的打开文件,文件中已经存有类的相关信息,所以在反序列化的时候必须要用同一个类才能反序列化成功,否则会抛出异常。

细节说明:

  1. 序列化的读写顺序要一致。
  2. 要求序列化或反序列化对象,需要在类中实现Serializable接口。
  3. 序列化的类中建议添加SerialVersonUID,为了提高版本兼容性。
private static final long serialVersionUID=1L;
  1. 序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员。
  2. 序列化对象时,要求里面属性的类型也要实现序列化接口。
  3. 序列化具备可继承性,也就是如果某类已经实现了序列化,则他的所有子类也已经默认实现了序列化。

六、标准输入输出流

在这里插入图片描述

七、转换流InputStreamReader和OutputStreamWriter(把字节流转成一个字符流)

中文在文件中大多默认按照UTF-8编码,流读取数据也默认采用UTF-8格式,但是这样在读取ANSI(gbk国标码)中文的时候会出现乱码。

类图

在这里插入图片描述
在这里插入图片描述

介绍

  1. InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)。
  2. OutputStreamWriter:Writer的子类,可以将OutputStream(字节流)包装成Writer(字符流)。
  3. 当处理纯文本数据时,使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流。
  4. 可以在使用指定格式编码格式(比如UTF-8、gbk、gb2312、ISO8859-1等)。

InputStreamReader用法介绍

在这里插入图片描述InputStreamReader只是作为一个转换的中间工具。

示例代码:

import java.io.*;

public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        String filePath="D:\\Java_code\\LearnPlus\\news5.txt";
        //news5.txt为ANSI编码文件,按照字符编码FileInputStream读取会乱码
        
        //把FileStreamReader转成InputStreamReader
        InputStreamReader inputStreamReader=new InputStreamReader(new FileInputStream(filePath),"gbk");

        //把InputStreamReader传入BufferedReader
        BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
        //读取
        String str=bufferedReader.readLine();
        System.out.println(str);

        bufferedReader.close();//关闭最外层的流
    }
}

OutputStreamWriter用法介绍

在这里插入图片描述
示例代码:

import java.io.*;

public class OutputStreamWriter_ {


    public static void main(String[] args) throws IOException {
        //把FileOutputStream字节流转成字符流OutputStreamWriter  只定编码gbk/utf-8/utf8
        String filePath="D:\\Java_code\\LearnPlus\\news6.txt";

        OutputStreamWriter outputStreamWriter=new OutputStreamWriter(new FileOutputStream(filePath),"gbk");
        outputStreamWriter.write("老色批");
        outputStreamWriter.close();

    }
}

八、打印流PrintStream和PrintWriter

打印流只有输出流,没有输入流。

类图

在这里插入图片描述在这里插入图片描述

PrintStream用法介绍

PrintStream是字节流

PrintWriter用法介绍

PrintWriter是字符流

九、总结:字符读取和字节读取的区别

  • 字符读取用String对象接收数据,多用于操作文本文件,不能操作二进制文件,会出现乱码。
  • 字节读取用byte数组接收数据,多用于操作二进制文件,也能操作字符文件,但是处理效率较低。
  • 常用的二进制文件有:图片、视频、doc、PDF等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值