12 IO流

12 IO流

12.1 File类

12.1.1 引入

【1】文件,文件夹(目录)
【2】查看文件/目录的信息
右键-属性
【3】在java程序中操纵文件/目录?怎么办?
java程序,最典型的特点:面向对象,java程序最擅长的就是操纵对象,这个对象属于File类。

12.1.2 对文件进行操作

package com.liweixiao.file;

import java.io.File;
import java.io.IOException;

/**
 * @author:LiWeixiao
 * @date:2023/1/11
 * @description:
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //将文件封装为一个File类对象
        File f = new File("e:\\test.txt");
        File f1 = new File("e:\\test.txt");
        File f2 = new File("e:/test.txt");
        //File.separator获取当前操作系统的路径拼接符号
        File f3 = new File("e:"+File.separator+"test.txt");//建议使用这种

        //常用方法
        System.out.println("文件是否可读:"+f.canRead());
        System.out.println("文件是否可写:"+f.canWrite());
        System.out.println("文件名称:"+f.getName());
        System.out.println("文件上级目录:"+f.getParent());
        System.out.println("是否目录:"+f.isDirectory());
        System.out.println("是否文件:"+f.isFile());
        System.out.println("文件是否隐藏:"+f.isHidden());
        System.out.println("文件大小:"+f.length());

        System.out.println("是否存在:"+f.exists());
        /*if(f.exists()){//如果文件存在,删除文件
            f.delete();
        }else {//如果文件不存在,创建文件
            f.createNewFile();
        }*/

        System.out.println(f == f1);//比较两个对象的地址
        System.out.println(f.equals(f1));//比较两个对象对应的文件路径

        //跟路径相关
        System.out.println("文件绝对路径:"+f.getAbsolutePath());
        System.out.println("文件相对路径:"+f.getPath());
        System.out.println("toString:"+f.toString());

        File f5 = new File("demo.txt");
        if(! f5.exists()){
            f5.createNewFile();
        }
        System.out.println("文件绝对路径:"+f5.getAbsolutePath());
        System.out.println("文件相对路径:"+f5.getPath());
        System.out.println("toString:"+f5.toString());

        File f6 = new File("a/b/c/demo.txt");
        /*if(! f6.exists()){
            f6.createNewFile();
        }*/
        System.out.println("文件绝对路径:"+f6.getAbsolutePath());
        System.out.println("文件相对路径:"+f6.getPath());
        System.out.println("toString:"+f6.toString());
    }
}

12.1.3 对目录进行操作

package com.liweixiao.file;

import java.io.File;

/**
 * @author:LiWeixiao
 * @date:2023/1/11
 * @description:
 */
public class Test02 {
    public static void main(String[] args) {
        //将目录封装为File类的对象
        File f = new File("E:\\hw\\IdeaProjects");
        //常用方法
        System.out.println("是否可读:"+f.canRead());
        System.out.println("是否可写:"+f.canWrite());
        System.out.println("名称:"+f.getName());
        System.out.println("上级目录:"+f.getParent());
        System.out.println("是否目录:"+f.isDirectory());
        System.out.println("是否文件:"+f.isFile());
        System.out.println("是否隐藏:"+f.isHidden());
        System.out.println("大小:"+f.length());
        System.out.println("是否存在:"+f.exists());

        //跟路径相关
        System.out.println("绝对路径:"+f.getAbsolutePath());
        System.out.println("相对路径:"+f.getPath());
        System.out.println("toString:"+f.toString());

        //跟目录相关的方法:
        File f2 = new File("E:\\a\\b\\c");
        //创建目录
        //f2.mkdir();//创建单层目录
        //f2.mkdirs();//创建多层目录
        //删除目录
        f2.delete();//删除目录,只会删除一层,前提:这层目录是空的,没有子目录或文件。
        //查看
        System.out.println("/////////////");
        String[] list = f.list();//文件夹下目录/文件的数组
        for(String s:list){
            System.out.println(s);
        }
        System.out.println("--------------");
        File[] files = f.listFiles();//作用更加广泛
        for(File file:files){
            System.out.println(file.getName()+","+file.getAbsolutePath());
        }
    }
}

12.2 IO流

12.2.1 引入

【1】File类:封装文件/目录的各种信息,对目录/文件进行操作,但是不能获取文件/目录中的内容
【2】引入IO流
I/O:Input/Output的缩写,用于处理设备之间的数据的传输。
【3】理解:一根管

以上图片来自网络

【4】IO流的体系结构

以上图片来自网络

12.2.2 FileReader、FileWriter字符流

【FileReader输入字符流】
【1】一个字符一个字符的将文件中内容读取到程序中

package com.liweixiao.io01;

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

/**
 * @author:LiWeixiao
 * @date:2023/1/11
 * @description:
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //文件->程序
        //1.有一个文件->创建一个file类的对象
        File f = new File("e:\\test.txt");
        //2.利用FileReader,怼到源文件->创建FileReader流的对象
        FileReader fr = new FileReader(f);
        //3.进行“吸”的动作->读取动作
        /*int n1 = fr.read();
        System.out.println(n1);
        int n2 = fr.read();
        System.out.println(n2);
        int n3 = fr.read();
        System.out.println(n3);
        int n4 = fr.read();
        System.out.println(n4);
        int n5 = fr.read();
        System.out.println(n5);
        int n6 = fr.read();
        System.out.println(n6);//文件的结尾处,读取内容为-1*/
        //方式1
        /*int n = fr.read();
        while (n != -1){
            System.out.println(n);
            n=fr.read();
        }*/
        //方式2
        int n;
        while ((n=fr.read()) != -1){
            System.out.println("uncode:"+n+",字符:"+(char)n);
        }
        //4.“管”不用了关闭->关闭流
        //流、数据库、网络资源,靠jvm本身没有办法自动关闭,需要程序员手动关闭
        fr.close();
    }
}

【2】一次性读取多个字符,缓冲数组

package com.liweixiao.io01;

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

/**
 * @author:LiWeixiao
 * @date:2023/1/11
 * @description:
 */
public class Test02 {
    public static void main(String[] args) throws IOException {
        //文件->程序
        //1.创建一个file类的对象
        File f = new File("e:\\test.txt");
        //2.创建FileReader流的对象
        FileReader fr = new FileReader(f);
        //3.读取动作
        //引入一个“快递员的小车”,一次拉5个快递
        char[] ch = new char[5];
        int len = fr.read(ch);//一次读取五个,返回这个数组中的有效长度
        while (len != -1){//文件的结尾处,读取内容为-1
            //错误方式
            /*for (int i = 0; i < ch.length; i++) {
                System.out.println(ch[i]);
            }*/
            //正确方式1
            /*for (int i = 0; i < len; i++) {
                System.out.print(ch[i]);
            }*/
            //正确方式2
            String s = new String(ch,0,len);
            System.out.print(s);
            len=fr.read(ch);
        }
        // 4.关闭流
        fr.close();
    }
}

【FileWriter字符流输出字符流】
【1】一个字符一个字符的向外输出

package com.liweixiao.io01;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
 * @author:LiWeixiao
 * @date:2023/1/11
 * @description:
 */
public class Test03 {
    public static void main(String[] args) throws IOException {
        //1.有一个目标文件
        File f = new File("e:\\demo.txt");
        //2.输出流
        FileWriter fw = new FileWriter(f);//1.目标文件不存在,会自动创建文件。
        //FileWriter fw = new FileWriter(f,false);//目标文件存在,默认false覆盖操作。
        //FileWriter fw = new FileWriter(f,true);//目标文件不存在,设置true追加操作。
        //3.输出
        //一个字符一个字符的输出
        String str = "hello你好";
        for (int i = 0; i < str.length(); i++) {
            fw.write(str.charAt(i));
        }
        //4.关闭流
        fw.close();
    }
}

【2】一次性写多个字符的向外输出,利用缓冲数组

package com.liweixiao.io01;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
 * @author:LiWeixiao
 * @date:2023/1/11
 * @description:
 */
public class Test04 {
    public static void main(String[] args) throws IOException {
        //1.有一个目标文件
        File f = new File("e:\\demo.txt");
        //2.输出流
        FileWriter fw = new FileWriter(f);
        //3.输出
        //一次多个字符输出,利用缓冲数组
        String str = "abchello你好老师";
        char[] chars = str.toCharArray();
        fw.write(chars);
        //4.关闭流
        fw.close();
    }
}

【3】利用FileReader、FileWriter文件复制

package com.liweixiao.io01;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/1/11
 * @description:
 */
public class Test04 {
    public static void main(String[] args) throws IOException {
        //1.有一个源文件
        File f1 = new File("e:\\test.txt");
        //2.有一个目标文件
        File f2 = new File("e:\\demo.txt");
        //3.搞一个输入的管,怼到源文件
        FileReader fr = new FileReader(f1);
        //4.搞一个输出的管,怼到目标文件
        FileWriter fw = new FileWriter(f2);

        //5.开始读取
        //方式1:一个字符一个字符的复制
        /*int n=fr.read();
        while (n != -1){
            fw.write(n);
            n = fr.read();
        }*/
        //方式2:利用一个缓冲数组
        /*char[] ch = new char[5];
        int len = fr.read(ch);
        while (len != -1){
            fw.write(ch,0, len);
            len =fr.read(ch);
        }*/
        //方式3:利用一个缓冲数组,将数组转成字符串
        char[] ch = new char[5];
        int len = fr.read(ch);
        while (len != -1){
            String s = new String(ch, 0, len);
            fw.write(s);
            len=fr.read(ch);
        }

        //6.关闭流,倒着关闭,后用先关
        fw.close();
        fr.close();
    }
}

警告-不要用字符流去操作非文本文件

文本文件:.txt、.java、.c、.cpp,建议使用字符流操作
非文本文件:.jpg、.mp3、.MP4、.doc、.ppt,建议使用字节流操作

12.3 利用try-catch-finally处理异常方式

实际开发中,使用try-catch解决异常

package com.liweixiao.io01;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/1/11
 * @description:
 */
public class Test04 {
    public static void main(String[] args) {
        //1.有一个源文件
        File f1 = new File("e:\\test.txt");
        //2.有一个目标文件
        File f2 = new File("e:\\demo.txt");
        //3.搞一个输入的管,怼到源文件
        FileReader fr = null;
        FileWriter fw=null;
        try {
            fr = new FileReader(f1);
            //4.搞一个输出的管,怼到目标文件
            fw = new FileWriter(f2);

            //5.开始读取
            //方式3:利用一个缓冲数组,将数组转成字符串
            char[] ch = new char[5];
            int len = fr.read(ch);
            while (len != -1){
                String s = new String(ch, 0, len);
                fw.write(s);
                len=fr.read(ch);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //6.关闭流,倒着关闭,后用先关
            try {
                if(fw != null){
                    fw.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            try {
                if(fr != null){
                    fr.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }


    }
}

12.2.3 FileInputStream、FileOutputStream字节流

【FileInputStream字节流读取文件中内容】
【1】字节流读取文本文件

package com.liweixiao.io02;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * @author:LiWeixiao
 * @date:2023/1/12
 * @description:
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //1.源文件
        File f = new File("e:\\test.txt");
        //2.搞一根管怼到源文件
        FileInputStream fis = new FileInputStream(f);
        //3.读取
        /*
        细节1:文件是utf-8存储的,英文占1个字节,中文占3个字节。
        细节2:如果是文本文件,不要使用字节流,建议使用字节流。
        细节3:read()读取一个字节,返回值是int类型,不是byte类型。
        byte取值范围-128~127。read()底层做了处理,返回都是正数,避免返回-1。
        */
        int n = fis.read();
        while (n != -1){
            System.out.println(n+","+(char)n);
            n=fis.read();
        }
        //4.关闭流
        fis.close();
    }
}

【2】字节流读取非文本文件(以图片为例),一个一个字节读取

package com.liweixiao.io02;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * @author:LiWeixiao
 * @date:2023/1/12
 * @description:
 */
public class Test02 {
    public static void main(String[] args) throws IOException {
        //1.源文件
        File f = new File("e:\\test.jpg");
        //2.字节流的管
        FileInputStream fis = new FileInputStream(f);
        //3.读取
        int count=0;
        int n = fis.read();
        while (n != -1){
            System.out.println(n);
            n=fis.read();
            count++;
        }
        System.out.println("字节:"+count);
        //4.关闭流
        fis.close();
    }
}

【3】利用缓冲数组

package com.liweixiao.io02;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author:LiWeixiao
 * @date:2023/1/12
 * @description:
 */
public class Test03 {
    public static void main(String[] args) throws IOException {
        //1.源文件
        File f = new File("e:\\test.jpg");
        //2.字节流的管
        FileInputStream fis = new FileInputStream(f);
        //3.读取
        byte[] b = new byte[1024*6];
        int len = fis.read(b);
        while (len != -1){
            for (int i = 0; i < len; i++) {
                System.out.println(b[i]);
            }
            len =fis.read(b);
        }
        //4.关闭流
        fis.close();
    }
}

【FileInputStream、FileOutputStream完成非文本文件的复制】
【1】读入一个字节,写出一个字节

package com.liweixiao.io02;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/2
 * @description:
 */
public class Test04 {
    public static void main(String[] args) throws IOException {
        //功能:完成图片的复制
        //1.原文件
        File f1 = new File("e:\\test.jpg");
        //2.目标文件
        File f2 = new File("e:\\test1.jpg");
        //3.一根输入管,怼到源文件
        FileInputStream fis = new FileInputStream(f1);
        //4.一根输出管,怼到目标文件
        FileOutputStream fos = new FileOutputStream(f2);
        //5.开始复制,边读边写
        int n = fis.read();
        while (n != -1){
            fos.write(n);
            //System.out.println(n);
            n = fis.read();
        }
        //6.关闭流,倒着关
        fos.close();
        fis.close();
    }
}

【2】利用缓冲字节数组,批量复制

package com.liweixiao.io02;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author:LiWeixiao
 * @date:2023/2/2
 * @description:
 */
public class Test05 {
    public static void main(String[] args) throws IOException {
        //功能:完成图片的复制
        //1.原文件
        File f1 = new File("e:\\test.jpg");
        //2.目标文件
        File f2 = new File("e:\\test1.jpg");
        //3.一根输入管,怼到源文件
        FileInputStream fis = new FileInputStream(f1);
        //4.一根输出管,怼到目标文件
        FileOutputStream fos = new FileOutputStream(f2);
        //5.开始复制,边读边写
        //利用缓冲数组
        byte[] b = new byte[1024 * 8];
        int len = fis.read(b);
        while (len != -1){
            fos.write(b,0, len);
            //System.out.println(len);
            len =fis.read(b);
        }
        //6.关闭流,倒着关
        fos.close();
        fis.close();
    }
}

12.2.4 BufferedInputStream、BufferedOutputStream缓冲字节流

【1】读入一个字节,写出一个字节

【2】利用缓冲字节数组

【3】利用缓冲区

以上图片来自网络

想要完成上面的效果,使用FileInputStream、FileOutputStream不能实现。
需要功能的加强,需要引入新的流,在FileInputStream、FileOutputStream外面再套一层流,BufferedInputStream、BufferedOutputStream缓冲流/处理流

package com.liweixiao.io02;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/8
 * @description:
 */
public class Test06 {
    public static void main(String[] args) throws IOException {
        //1.原图片
        File f1 = new File("E:\\test.jpg");
        //2.目标图片
        File f2 = new File("E:\\test1.jpg");
        //3.输入管
        FileInputStream fis = new FileInputStream(f1);
        //4.输出管
        FileOutputStream fos = new FileOutputStream(f2);
        //5.功能加强,在FileInputStream外面套一个管BufferedInputStream
        BufferedInputStream bis = new BufferedInputStream(fis);
        //6.功能加强,在FileOutputStream外面套一个管BufferedOutputStream
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        //7.开始动作
        byte[] b = new byte[1024 * 8];
        int len = bis.read(b);
        while (len != -1){
            bos.write(b,0,len);
            /* bos.flush(); 底层已经帮我们做了刷新缓冲区的操作,不用我们手动完成:底层调用flushBuffer()*/
            len = bis.read(b);
        }

        //8.关闭流
        // 倒着关
        //如果处理流包裹着节点流,那么只要关闭高级流(处理流),那么里面的字节流(fos、fis)会随之被关闭。
        bos.close();
        bis.close();
        /*fos.close();
        fis.close();*/
    }
}

比对非文本文件复制的三种方法的效率

long startTime = System.currentTimeMillis();
long endTime = System.currentTimeMillis();
System.out.println("复制完成的时间:"+(endTime-startTime)+"毫秒");

耗时:一个一个字节 > 缓冲字节数组 > 缓冲区

12.2.5 BufferedReader、BufferedWriter缓冲字符流

package com.liweixiao.io02;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/8
 * @description:
 */
public class Test07 {
    public static void main(String[] args) throws IOException {
        //1.原文件
        File f1 = new File("e:\\test.txt");
        //2.目标文件
        File f2 = new File("e:\\test1.txt");
        //3.输入字符管
        FileReader fr = new FileReader(f1);
        //4.输出字符管
        FileWriter fw = new FileWriter(f2);
        //5.加强功能,套一个缓冲输入管
        BufferedReader br = new BufferedReader(fr);
        //6.加强功能,套一个缓冲输出管
        BufferedWriter bw = new BufferedWriter(fw);

        //7.复制操作
        //方式1
        /*int n = br.read();
        while (n != -1){
            bw.write(n);
            n=br.read();
        }*/

        //方式2
        /*char[] ch = new char[30];
        int len = br.read(ch);
        while (len != -1){
            bw.write(ch,0,len);
            len=br.read(ch);
        }*/

        //方式3
        String str = br.readLine();//每次读取一行
        while (str != null){
            bw.write(str);
            //在文本文件中应该再写出一个换行
            bw.newLine();
            str=br.readLine();
        }

        //8.关闭流
        bw.close();
        br.close();
    }
}

12.2.6 InputStreamReader、OutpuStreamWriter转换流

作用:将字节流和字符流进行转换
属于字符流,通过后缀
InputStreamReader:字节输入流 -> 字符输入流
OutputStreamWriter:字符输出流 -> 字节输出流

package com.liweixiao.io03;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/8
 * @description:
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //1.原文件
        File f1 = new File("e:\\test.txt");
        //2.输入字节流
        FileInputStream fis = new FileInputStream(f1);
        //3.加入一个转换流,字节流转换为字符流
        //将字节转换为字符的时候,需要指定一个编码,这个编码跟文件本身的编码格式统一
        //如果编码格式不统一,出现乱码
        //如果不写,获取程序本身的编码格式,已设置为utf-8
        InputStreamReader isr = new InputStreamReader(fis,"utf-8");
        //4.开始动作
        char[] ch = new char[20];
        int len = isr.read(ch);
        while (len != -1){
            //如果使用println,一行超过ch的长度将换行,所以此处使用print
            System.out.print(new String(ch,0,len));
            len=isr.read(ch);
        }
        //5.关闭流
        isr.close();
        fis.close();
    }
}

【InputStreamReader、OutpuStreamWriter转换流实现文本文件的复制】

package com.liweixiao.io03;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/8
 * @description:
 */
public class Test02 {
    public static void main(String[] args) throws IOException {
        //1.原文件
        File f1 = new File("e:\\test.txt");
        //2.目标文件
        File f2 = new File("e:\\test1.txt");
        //3.输入字节流FileInputStream
        FileInputStream fis = new FileInputStream(f1);
        //4.输出字节流FileOutputStream
        FileOutputStream fos = new FileOutputStream(f2);
        //5.转换输入流InputStreamReader
        InputStreamReader isr = new InputStreamReader(fis,"utf-8");
        //6.转换输出流OutputStreamWriter
        OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");

        //7.复制
        char[] ch = new char[20];
        int len = isr.read(ch);
        while (len != -1){
            osw.write(ch,0,len);
            len=isr.read(ch);
        }

        //8.关闭流
        osw.close();
        isr.close();
    }
}

12.4 System类对IO流的支持

【1】System的属性:
System.in:“标准”输入流 -> 默认情况下 从键盘输入
System.out:“标准”输出流 -> 默认情况下 输出到控制台
【2】System.in

package com.liweixiao.io04;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

/**
 * @author:LiWeixiao
 * @date:2023/2/8
 * @description:
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //得到一个标准输入流,从键盘输入
        /*InputStream in = System.in;
        //调用方法
        int n = in.read();//read方法等待键盘的录入,所以这个方法是一个阻塞方法。
        System.out.println(n);//输入a输出(ascii码)97*/

        //案例,从键盘录入一个int类型的数据
        //从上面代码证明,键盘录入实际是System.in
        //形象的理解:System.in是一根管,怼到键盘上,从键盘上录入到程序中
        //Scanner作用:扫描器,扫键盘从这根管出来的数据
        /*Scanner sc = new Scanner(System.in);
        int i = sc.nextInt();
        System.out.println(i);*/

        //既然Scanner是扫描的作用,不一定非得扫System.in进来的数据,还可以扫描其它管的内容
        Scanner sc = new Scanner(new FileInputStream(new File("e:\\test.txt")));
        while (sc.hasNext()){
            System.out.println(sc.next());
            sc.hasNext();
        }
    }
}

【3】System.out

package com.liweixiao.io04;

import java.io.PrintStream;

/**
 * @author:LiWeixiao
 * @date:2023/2/8
 * @description:
 */
public class Test02 {
    public static void main(String[] args) {
        //写到控制台
        PrintStream out = System.out;
        //调用方法
        out.print("你好1");//直接在控制台写出,不换行
        out.print("你好2");
        out.println("你好3");//换行
        out.println("你好4");
        out.println("你好5");
        System.out.println("你好6");
    }
}

【键盘录入内容保存到文本】

以上图片来自网络

package com.liweixiao.io04;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/9
 * @description:
 */
public class Test03 {
    public static void main(String[] args) throws IOException {
        //1.先准备输入方向
        //键盘录入
        InputStream is = System.in;
        //字节流转换字符流
        InputStreamReader isr = new InputStreamReader(is);
        //输入缓冲流,增强功能
        BufferedReader br = new BufferedReader(isr);

        //2.输出方向
        //目标文件
        File f2 = new File("e:\\demo1.txt");
        //输出字符流
        FileWriter fw = new FileWriter(f2);
        //输出缓冲流,增强功能
        BufferedWriter bw = new BufferedWriter(fw);

        //3.开始动作
        String s = br.readLine();
        //while (s != null){//这样写有问题
        while (! s.equals("exit")){
            bw.write(s);
            bw.newLine();//文件中换行
            s=br.readLine();
        }

        //4.关闭流
        bw.close();
        br.close();
    }
}

12.2.7 DataInputStream、DataOutputStream数据流(不重要,了解即可)

【1】数据流:用来操作基本数据类型和字符串的
【2】
DataInputStream:将文件中存储的基本数据类型和字符串 写入 内存的变量中
DataOutputStream:将内存中的基本数据类型和字符串的变量 写出 文件中
【利用DataOutputStream向外写出变量】

package com.liweixiao.io05;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/9
 * @description:
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //DataOutputStream:将内存中基本类型和字符串的变量 写出 文件中
        File f1 = new File("e:\\test.txt");
        FileOutputStream fos = new FileOutputStream(f1);
        DataOutputStream dos = new DataOutputStream(fos);
        //new DataOutputStream(new FileOutputStream(new File("e:\\test.txt")));

        //将变量写到文件中
        dos.writeUTF("你好");
        dos.writeBoolean(false);
        dos.writeDouble(6.9);

        //关闭流
        dos.close();
    }
}

写到文件中的是乱码,是给程序看的

【利用DataInputStream读取变量】

package com.liweixiao.io05;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/9
 * @description:
 */
public class Test02 {
    public static void main(String[] args) throws IOException {
        //DataInputStream
        DataInputStream dis = new DataInputStream(new FileInputStream(new File("e:\\test.txt")));

        //将文件中内容读取到程序中
        System.out.println(dis.readUTF());
        System.out.println(dis.readBoolean());
        System.out.println(dis.readDouble());
        System.out.println(dis.readInt());

        //关闭流
        dis.close();
    }
}

12.2.8 ObjectInputStream、ObjectOutputStream对象流

【1】对象流ObjectInputStream、ObjectOutputStream
用于存储和读取基本数据类型数据或对象的处理流。
它的强大之处就是可以把java中的对象写入到数据源中,也能把对象从数据源中还原回来。
【2】序列号和反序列化
ObjectOutputStream类:把内存中的Java对象转换成平台无关的二进制数据,从而允许把这种二进制数据持久保存在磁盘上,或通过网络将二进制数据传输到另一个网络节点。 -> 序列化
ObjectInputStream类:当其它程序获取了这种二进制数据,就可以恢复成原来的java对象。 -> 反序列化

【3.1将字符串写入到文件中,序列化】

package com.liweixiao.io06;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/9
 * @description:
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //将内存中的字符串写到文件中
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("e:\\test.txt")));

        //字符串写出
        oos.writeObject("你好");

        //关闭流
        oos.close();
    }
}

查看文件,乱码,是给程序看的。

【3.2读取文本中字符串,反序列化】

package com.liweixiao.io06;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/9
 * @description:
 */
public class Test02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //将文件中保存的字符串 读入 内存:
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("e:\\test.txt")));
        //读取字符串
        String s = (String) (ois.readObject());
        System.out.println(s);
        //关闭流
        ois.close();
    }
}

实现SeriaLizable接口

【4.1自定义类,序列化】
自定义类必须要实现一个接口,序列化

public interface Serializable {
}

接口内部,什么都没有,这种接口叫标识接口。
只要实现这个接口的类的对象才能序列化,否则不可以。

package com.liweixiao.io07;

/**
 * @author:LiWeixiao
 * @date:2023/2/9
 * @description:
 */
public class Person implements java.io.Serializable{
    private static final long serialVersionUID = -1178538688015123993L;
    //private static final long serialVersionUID = 12345L;

    //属性
    private String name;//姓名
    private int 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;
    }

    //构造器
    public Person() {
    }

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

    //方法
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.liweixiao.io07;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/9
 * @description:
 */
public class Test01 {
    public static void main(String[] args) throws IOException {
        //序列化:将内存中对象 写入 文件
        //有一个对象
        Person p = new Person("lili", 19);
        //有对象流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("e:\\test2.txt")));
        //向外写,序列化
        oos.writeObject(p);
        //关闭流
        oos.close();
    }
}

【4.2自定义类,反序列化】

package com.liweixiao.io07;

import java.io.*;

/**
 * @author:LiWeixiao
 * @date:2023/2/9
 * @description:
 */
public class Test02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //将文件中保存的对象 读入 内存
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("e:\\test2.txt")));
        //读取对象
        Person p = (Person) (ois.readObject());
        System.out.println(p);
        //关闭流
        ois.close();
    }
}

serialVersionUID

凡是实现Serializable接口(标识接口)的类都有一个表示序列化版本标识符的静态常量:
➢private static final long serialVersionUID;
➢serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序加化时是否兼容。
➢如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。

➢简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)

【IDEA配置】

以上图片来自网络

在Person类上 alt+enter
【序列化细节】
(1)被序列化的类的内部的所有属性,必须是可序列化的 (基本数据类型都是可序列化的)。
(2)static,transient修饰的属性 不可以被序列化。

posted @   LiWeixiao  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示