你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

11-IO(核心类库)

2021/12/15 11:49:31

感谢你的路过,希望学生的笔记能给你一点微不足道的参考(2/100)
Java基础思维导图,完整Java体系的链接

一,File类

1.1什么是File类?

   java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。

1.2File类的变量和类型

代码:

package com.wyh.File;
import java.io.File;

/*  File类的变量和类型
    java.io.File类
    文件和目录路径名的抽象表示形式。
    java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件和文件夹进行操作
    我们可以使用File类的方法
        创建一个文件/文件夹
        删除文件/文件夹
        获取文件/文件夹
        判断文件/文件夹是否存在
        对文件夹进行遍历
        获取文件的大小
    File类是一个与系统无关的类,任何的操作系统都可以使用这个类中的方法

    重点:记住这三个单词
        file:文件
        directory:文件夹/目录
        path:路径
 */
public class Demo01_File {
    public static void main(String[] args) {
        /*
            static String pathSeparator 与系统有关的路径分隔符,为了方便,它被表示为一个字符串。
            static char pathSeparatorChar 与系统有关的路径分隔符。

            static String separator 与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。
            static char separatorChar 与系统有关的默认名称分隔符。

            操作路径:路径不能写死了
            C:\develop\a\a.txt  windows
            C:/develop/a/a.txt  linux
            "C:"+File.separator+"develop"+File.separator+"a"+File.separator+"a.txt"
         */
        String pathSeparator = File.pathSeparator;
        System.out.println(pathSeparator);//路径分隔符 windows:分号;  linux:冒号:

        String separator = File.separator;
        System.out.println(separator);// 文件名称分隔符 windows:反斜杠\  linux:正斜杠/
    }
}

1.3绝对路径和相对路径

      绝对路径:从盘符开始的路径,这是一个完整的路径。
      相对路径:相对于项目目录的路径,这是一个便捷的路径,开发中经常使用。
      例子:插入xmind的文件,如果和之前插入的文件在一个目录下就是相对目录,如果去新的文件夹就是绝对路径。
代码:

package com.wyh.File;
import java.io.File;
/*
    路径:
        绝对路径:是一个完整的路径
            以盘符(c:,D:)开始的路径
                c:\\a.txt
                C:\\Users\itcast\\IdeaProjects\\shungyuan\\123.txt
                D:\\demo\\b.txt
        相对路径:是一个简化的路径
            相对指的是相对于当前项目的根目录(C:\\Users\itcast\\IdeaProjects\\shungyuan)
            如果使用当前项目的根目录,路径可以简化书写
            C:\\Users\itcast\\IdeaProjects\\shungyuan\\123.txt-->简化为: 123.txt(可以省略项目的根目录)
        注意:
            1.路径是不区分大小写
            2.路径中的文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠
 */
public class Demo02_File {
    public static void main(String[] args) {
        show01();
    }

    /*
        File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
        参数:把路径分成了两部分
            File parent:父路径
            String child:子路径
        好处:
             父路径和子路径,可以单独书写,使用起来非常灵活;父路径和子路径都可以变化
             父路径是File类型,可以使用File的方法对路径进行一些操作,再使用路径创建对象
     */
    private static void show03() {
        File parent = new File("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO");
        File file = new File(parent,"hello.java");
        System.out.println(file);//c:\hello.java
    }

    private static void show02(String parent, String child) {
        File file = new File(parent,child);
        System.out.println(file);//c:\a.txt
    }

    /*
     *路径
     */
    private static void show01() {
        File f1 = new File("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\a.txt");
        System.out.println("f1的路径"+f1.getAbsolutePath());// 绝对路径

        File f2 = new File("a.txt");
        System.out.println("f2的路径"+f2.getAbsolutePath());// 相对路径

    }
}

1.4File类的构造方法有?

   public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的File实例。
   public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的File实例。
   public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的File实例。在这里插入图片描述
   小贴士:
      1. 一个File对象代表硬盘中实际存在的一个文件或者目录
      2. 无论该路径下是否存在文件或者目录,都不影响File对象的创建

1.5File类的常用方法有?

   获取功能的方法
      public String getAbsolutePath() :返回此File的绝对路径名字符串。
      public String getPath() :将此File转换为路径名字符串。
      public String getName() :返回由此File表示的文件或目录的名称。
      public long length() :返回由此File表示的文件的长度。
      API中说明:length(),表示文件的长度。但是File对象表示目录,则返回值未指定
代码:

package com.wyh.File;
import java.io.File;

/*
    File类获取功能的方法
        - public String getAbsolutePath() :返回此File的绝对路径名字符串。
        - public String getPath() :将此File转换为路径名字符串。
        - public String getName()  :返回由此File表示的文件或目录的名称。
        - public long length()  :返回由此File表示的文件的长度。
 */
public class Demo03_File {
    public static void main(String[] args) {
        show03();
    }

    /*
        public long length()  :返回由此File表示的文件的长度。
        获取的是构造方法指定的文件的大小,以字节为单位
        注意:
            文件夹是没有大小概念的,不能获取文件夹的大小
            如果构造方法中给出的路径不存在,那么length方法返回0
     */
    private static void show04() {
        File f1 = new File("C:\\develop\\a\\1.jpg");
        long l1 = f1.length();
        System.out.println(l1);//780831字节

        File f2 = new File("C:\\develop\\a\\2.jpg");
        System.out.println(f2.length());//0

        File f3 = new File("C:\\develop\\a");
        System.out.println(f3.length());//0 文件夹没有大小概念的
    }

    /*
        public String getName()  :返回由此File表示的文件或目录的名称。
        获取的就是构造方法传递路径的结尾部分(文件/文件夹)
     */
    private static void show03() {
        File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\a.txt");
        String name1 = f1.getName();
        System.out.println(name1);//a.txt

        File f2 = new File("E:\\BaiduNetdiskDownload");
        String name2 = f2.getName();
        System.out.println(name2);//shungyuan
    }

    /*
        public String getPath() :将此File转换为路径名字符串。
        获取的构造方法中传递的路径

        toString方法调用的就是getPath方法
        源码:
            public String toString() {
                return getPath();
            }
     */
    private static void show02() {
        File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\a.txt");
        File f2 = new File("a.txt");
        String path1 = f1.getPath();
        System.out.println(path1);//C:\Users\itcast\IdeaProjects\shungyuan\a.txt
        String path2 = f2.getPath();
        System.out.println(path2);//a.txt

        System.out.println(f1);//C:\Users\itcast\IdeaProjects\shungyuan\a.txt
        System.out.println(f1.toString());//C:\Users\itcast\IdeaProjects\shungyuan\a.txt
    }

    /*
        public String getAbsolutePath() :返回此File的绝对路径名字符串。
        获取的构造方法中传递的路径
        无论路径是绝对的还是相对的,getAbsolutePath方法返回的都是绝对路径
     */
    private static void show01() {
        File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\a.txt");
        String absolutePath1 = f1.getAbsolutePath();
        System.out.println(absolutePath1);//C:\Users\itcast\IdeaProjects\shungyuan\a.txt

        File f2 = new File("a.txt");
        String absolutePath2 = f2.getAbsolutePath();
        System.out.println(absolutePath2);//C:\Users\itcast\IdeaProjects\shungyuan\a.txt
    }
}

   判断功能的方法
      public boolean exists() :此File表示的文件或目录是否实际存在。
      public boolean isDirectory() :此File表示的是否为目录。
      public boolean isFile() :此File表示的是否为文件。
代码:

package com.wyh.File;
import java.io.File;

/*
    File类判断功能的方法
        - public boolean exists() :此File表示的文件或目录是否实际存在。
        - public boolean isDirectory() :此File表示的是否为目录。
        - public boolean isFile() :此File表示的是否为文件。
 */
public class Demo04_File {
    public static void main(String[] args) {
        show02();
    }

    /*
        public boolean isDirectory() :此File表示的是否为目录。
            用于判断构造方法中给定的路径是否以文件夹结尾
                是:true
                否:false
        public boolean isFile() :此File表示的是否为文件。
            用于判断构造方法中给定的路径是否以文件结尾
                是:true
                否:false
        注意:
            电脑的硬盘中只有文件/文件夹,两个方法是互斥
            这两个方法使用前提,路径必须是存在的,否则都返回false
     */
    private static void show02() {
        File f1 = new File("D:\\KwDownload\\08_FileAndRecursion\\aaa\\z.txt");

        //不存在,就没有必要获取
        if(f1.exists()){
            System.out.println(f1.isDirectory());
            System.out.println(f1.isFile());
        }

        File f2 = new File("D:\\KwDownload\\08_FileAndRecursion\\111\\222\\333\\444");
        if(f2.exists()){
            System.out.println(f2.isDirectory());//true
            System.out.println(f2.isFile());//false
        }

        File f3 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\shungyuan.iml");
        if(f3.exists()){
            System.out.println(f3.isDirectory());//false
            System.out.println(f3.isFile());//true
        }

    }

    /*
        public boolean exists() :此File表示的文件或目录是否实际存在。
        用于判断构造方法中的路径是否存在
            存在:true
            不存在:false
     */
    private static void show01() {
        File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan");
        System.out.println(f1.exists());//true

        File f2 = new File("C:\\Users\\itcast\\IdeaProjects\\shung");
        System.out.println(f2.exists());//false

        File f3 = new File("shungyuan.iml");//相对路径 C:\Users\itcast\IdeaProjects\shungyuan\shungyuan.iml
        System.out.println(f3.exists());//true

        File f4 = new File("a.txt");
        System.out.println(f4.exists());//false
    }
}

   创建删除功能的方法
      public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
      public boolean delete() :删除由此File表示的文件或目录。
      public boolean mkdir() :创建由此File表示的目录。
      public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
      API中说明:
代码:

package com.wyh.File;
import java.io.File;
import java.io.IOException;

/*
    File类创建删除功能的方法
        - public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
        - public boolean delete() :删除由此File表示的文件或目录。
        - public boolean mkdir() :创建由此File表示的目录。
        - public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
 */
public class Demo05_File {
    public static void main(String[] args) throws IOException {
      show03();
    }
    /*
           public boolean delete() :删除由此File表示的文件或目录。
           此方法,可以删除构造方法路径中给出的文件/文件夹
           返回值:布尔值
               true:文件/文件夹删除成功,返回true
               false:文件夹中有内容,不会删除返回false;构造方法中路径不存在false
           注意:
               delete方法是直接在硬盘删除文件/文件夹,不走回收站,删除要谨慎
        */
    private static void show03() {
        File f1 = new File("08_FileAndRecursion\\新建文件夹");
        boolean b1 = f1.delete();
        System.out.println("b1:"+b1);

        File f2 = new File("08_FileAndRecursion\\abc.txt");
        System.out.println(f2.delete());
    }

    /*
      public boolean mkdir() :创建单级空文件夹
      public boolean mkdirs() :既可以创建单级空文件夹,也可以创建多级文件夹
      创建文件夹的路径和名称在构造方法中给出(构造方法的参数)
       返回值:布尔值
           true:文件夹不存在,创建文件夹,返回true
           false:文件夹存在,不会创建,返回false;构造方法中给出的路径不存在返回false
       注意:
           1.此方法只能创建文件夹,不能创建文件
    */
    private static void show02() {
        File f1 = new File("08_FileAndRecursion\\aaa");
        boolean b1 = f1.mkdir();
        System.out.println("b1:"+b1);

        File f2 = new File("08_FileAndRecursion\\111\\222\\333\\444");
        boolean b2 = f2.mkdirs();
        System.out.println("b2:"+b2);

        File f3 = new File("08_FileAndRecursion\\abc.txt");
        boolean b3 = f3.mkdirs();//看类型,是一个文件
        System.out.println("b3:"+b3);

        File f4 = new File("08_F\\ccc");
        boolean b4 = f4.mkdirs();//不会抛出异常,路径不存在,不会创建
        System.out.println("b4:"+b4);
    }
    /*
           public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
           创建文件的路径和名称在构造方法中给出(构造方法的参数)
           返回值:布尔值
               true:文件不存在,创建文件,返回true
               false:文件存在,不会创建,返回false
           注意:
               1.此方法只能创建文件,不能创建文件夹
               2.创建文件的路径必须存在,否则会抛出异常

           public boolean createNewFile() throws IOException
           createNewFile声明抛出了IOException,我们调用这个方法,就必须的处理这个异常,要么throws,要么trycatch
        */
    private static void show01() throws IOException {
        File f1 = new File("D:\\KwDownload\\08_FileAndRecursion\\1.txt");
        boolean b1 = f1.createNewFile();
        System.out.println("b1:"+b1);

        File f2 = new File("D:\\KwDownload\\08_FileAndRecursion\\2.txt");
        System.out.println(f2.createNewFile());

        File f3 = new File("D:\\KwDownload\\08_FileAndRecursion\\新建文件夹");
        System.out.println(f3.createNewFile());//不要被名称迷糊,要看类型

       /* File f4 = new File("08_FileAndRecursi\\3.txt");
        System.out.println(f4.createNewFile());//路径不存在,抛出IOException*/
    }
}

1.6目录的遍历

      public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
      public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
      小贴士:调用listFiles方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历。
代码:

package com.wyh.File;

import java.io.File;
import java.io.IOException;
import java.sql.SQLOutput;

/**
 * @Deacription File文件遍历
 * @Author 王宇辉
 * @Date 2021/9/3 20:39
 * @Version 1.0
 **/
public class Task01 {
    // Java.io.*
    public static void main(String[] args) throws IOException {
        File e = new File("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO");
        File[] files =e.listFiles();
        ListFiles(files);
    }

    private static void ListFiles(File[] files) {
        if (files!= null && files.length>0){
            for (File file:files) {
                if (file.isFile()){
                    // 文件
                    if (file.getName().endsWith(".txt")){
                        file.delete();
                        System.out.println(file.getAbsolutePath()+"已删除");
                    }
                }else{
                    // 文件夹
                    File[] files1 = file.listFiles();
                    ListFiles(files1);
                }
            }
        }
    }
}

二,文件过滤器

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

package com.wyh.File;
import java.io.File;
import java.io.FileFilter;
/*
    创建过滤器FileFilter的实现类,重写过滤方法accept,定义过滤规则
 */
public class FileFilterImpl implements FileFilter{
    @Override
    public boolean accept(File pathname) {
        /*
            过滤的规则:
            在accept方法中,判断File对象是否是以.java结尾
            是就返回true
            不是就返回false
         */
        //如果pathname是一个文件夹,返回true,继续遍历这个文件夹
        if(pathname.isDirectory()){
            return true;
        }
        return pathname.getName().toLowerCase().endsWith(".java");
    }
}
package com.wyh.File;

import java.io.File;

/**
 * @Deacription 文件过滤器
 * @Author 王宇辉
 * @Date 2021/9/3 21:13
 * @Version 1.0
 **/
public class Demo06_FileFilter {
    public static void main(String[] args) {
        File file = new File("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO");
        getAllFile(file);
    }

    /*
        定义一个方法,参数传递File类型的目录
        方法中对目录进行遍历
     */
    public static void getAllFile(File dir){
        File[] files = dir.listFiles(new FileFilterImpl());//传递过滤器对象
        for (File f : files) {
            //对遍历得到的File对象f进行判断,判断是否是文件夹
            if(f.isDirectory()){
                //f是一个文件夹,则继续遍历这个文件夹
                //我们发现getAllFile方法就是传递文件夹,遍历文件夹的方法
                //所以直接调用getAllFile方法即可:递归(自己调用自己)
                getAllFile(f);
            }else{
                //f是一个Java文件,直接打印即可
                System.out.println(f);
            }
        }
    }
}
package com.wyh.File;
import java.io.File;

/*
    需求:
        遍历c:\\abc文件夹,及abc文件夹的子文件夹
        只要.java结尾的文件
        c:\\abc
        c:\\abc\\abc.txt
        c:\\abc\\abc.java
        c:\\abc\\a
        c:\\abc\\a\\a.jpg
        c:\\abc\\a\\a.java
        c:\\abc\\b
        c:\\abc\\b\\b.java
        c:\\abc\\b\\b.txt
    我们可以使用过滤器来实现
    在File类中有两个和ListFiles重载的方法,方法的参数传递的就是过滤器
    File[] listFiles(FileFilter filter)
    java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器。
        作用:用来过滤文件(File对象)
        抽象方法:用来过滤文件的方法
            boolean accept(File pathname) 测试指定抽象路径名是否应该包含在某个路径名列表中。
            参数:
                File pathname:使用ListFiles方法遍历目录,得到的每一个文件对象
    File[] listFiles(FilenameFilter filter)
    java.io.FilenameFilter接口:实现此接口的类实例可用于过滤器文件名。
        作用:用于过滤文件名称
        抽象方法:用来过滤文件的方法
            boolean accept(File dir, String name) 测试指定文件是否应该包含在某一文件列表中。
            参数:
                File dir:构造方法中传递的被遍历的目录
                String name:使用ListFiles方法遍历目录,获取的每一个文件/文件夹的名称
    注意:
        两个过滤器接口是没有实现类的,需要我们自己写实现类,重写过滤的方法accept,在方法中自己定义过滤的规则
 */
public class Demo07_FileFilter {
    public static void main(String[] args) {
        File file = new File("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO");
        getAllFile(file);
    }

    /*
        定义一个方法,参数传递File类型的目录
        方法中对目录进行遍历
     */
    public static void getAllFile(File dir){
        //传递过滤器对象 使用匿名内部类
        /*File[] files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                //过滤规则,pathname是文件夹或者是.java结尾的文件返回true
                return pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java");
            }
        });*/

        //使用Lambda表达式优化匿名内部类(接口中只有一个抽象方法)
        /*File[] files = dir.listFiles((File pathname)->{
            return pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java");
        });*/

        File[] files = dir.listFiles(pathname->pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java"));

        /*File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                //过滤规则,pathname是文件夹或者是.java结尾的文件返回true
                return new File(dir,name).isDirectory() || name.toLowerCase().endsWith(".java");
            }
        });*/

        //使用Lambda表达式优化匿名内部类(接口中只有一个抽象方法)
        /*File[] files = dir.listFiles((File d, String name)->{
            //过滤规则,pathname是文件夹或者是.java结尾的文件返回true
            return new File(d,name).isDirectory() || name.toLowerCase().endsWith(".java");
        });*/

        //File[] files = dir.listFiles((d,name)->new File(d,name).isDirectory() || name.toLowerCase().endsWith(".java"));

        for (File f : files) {
            //对遍历得到的File对象f进行判断,判断是否是文件夹
            if(f.isDirectory()){
                //f是一个文件夹,则继续遍历这个文件夹
                //我们发现getAllFile方法就是传递文件夹,遍历文件夹的方法
                //所以直接调用getAllFile方法即可:递归(自己调用自己)
                getAllFile(f);
            }else{
                //f是一个文件,直接打印即可
                System.out.println(f);
            }
        }
    }
}

三,IO概述

3.1什么是IO?

   我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为 输入input 和 输出 output ,即流向内存是输入流,流出内存的输出流。
   Java中I/O操作主要是指使用 java.io 包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写 出数据

3.2IO的分类

   根据数据的流向
      输入流 :把数据从 其他设备 上读取到 内存 中的流
      输出流 :把数据从 内存 中写出到 其他设备 上的流
   格局数据的类型
      字节流 :以字节为单位,读写数据的流
      字符流 :以字符为单位,读写数据的流

3.3IO的流向说明图解

在这里插入图片描述

3.4顶级父类们

   字节流
      字节输入流 InputStream
      字节输出流 OutputStream
   字符流
      字符输入流 Reader
      字符输出流 Writer

四,字节流

4.1一切皆为字节?

   以二进制数字的形式保存,都一个一个的字节,那么传输时一 样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底 层传输的始终为二进制数据。

4.2字节输出流【OutputStream】

   介绍:java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。
   基本共性功能方法
      public void close() :关闭此输出流并释放与此流关联的所有系统资源。
      public void flush() :刷新此输出流并强制写出任何缓冲的输出字节。
      public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流
      public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输 出到此输出流
      public abstract void write(int b) :将指定的字节写入此输出流
   小贴士:
      close方法,当完成流的操作时,必须调用此方法,释放系统资源

4.3FileOutputStream类

   介绍:java.io.FileOutputStream 类是文件输出流,用于将数据写出到文件
   构造方法:
      public FileOutputStream(File file) :创建文件输出流以写入由指定的 File对象表示的文件。
      public FileOutputStream(String name) :创建文件输出流以写入具有指定名称的文件
   写出字节数据
      1. 写出字节:write(int b) 方法,每次可以写出一个字节数据
   小贴士:
      1. 虽然参数为int类型四个字节,但是只会保留一个字节的信息写出。
      2. 流操作完毕后,必须释放系统资源,调用close方法,千万记得。
      2. 写出字节数组: write(byte[] b) ,每次可以写出数组中的数据
      3. 写出指定长度字节数组: write(byte[] b, int off, int len) ,每次写出从off索引开始,len个字节
   数据追加续写
      用途:保留目标文件中数据,还能 继续添加新数据
      方法
         public FileOutputStream(File file, boolean append) :创建文件输出流以写入由指定的 File对象表示的文件。
         public FileOutputStream(String name, boolean append) :创建文件输出流以写入具有指定名称的文件。
代码:

package com.wyh.Io;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

/**
 * @Deacription 字节输出流-FileOutputStream类
 * @Author 王宇辉
 * @Date 2021/9/4 8:21
 * @Version 1.0
 **/
public class Demo08_OutputStream {

    public static void main(String[] args) throws IOException {
        demo03();
    }

    /**
     * 字节输出流的基本使用
     * @throws IOException
     */
    public static void demo01() throws IOException {
        //1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
        FileOutputStream fos = new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\b.txt");
        //2.调用FileOutputStream对象中的方法write,把数据写入到文件中
        //public abstract void write(int b) :将指定的字节输出流。
        fos.write(97);
        //3.释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)
        fos.close();
    }

    /*
    一次写多个字节的方法:
        - public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
        - public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
    */
    public static void demo02() throws IOException{
        //创建FileOutputStream对象,构造方法中绑定要写入数据的目的地
        FileOutputStream fos = new FileOutputStream(new File("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt"));
        //调用FileOutputStream对象中的方法write,把数据写入到文件中
        //在文件中显示100,写个字节
        fos.write(49);
        fos.write(48);
        fos.write(48);

        /*
            public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
            一次写多个字节:
                如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表
                如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表(GBK)
         */
        byte[] bytes = {65,66,67,68,69};//ABCDE
        fos.write(bytes);

         /*
            public void write(byte[] b, int off, int len) :把字节数组的一部分写入到文件中
                int off:数组的开始索引
                int len:写几个字节
         */
        fos.write(bytes,1,2);//BC

         /*
            写入字符的方法:可以使用String类中的方法把字符串,转换为字节数组
                byte[] getBytes()  把字符串转换为字节数组
         */
        byte[] bytes2 = "你好".getBytes();
        System.out.println(Arrays.toString(bytes2));//[-28, -67, -96, -27, -91, -67]
        fos.write(bytes2);

        //释放资源
        fos.close();
    }

    /*
        追加写/续写:使用两个参数的构造方法
            FileOutputStream(String name, boolean append)创建一个向具有指定 name 的文件中写入数据的输出文件流。
            FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
            参数:
               String name,File file:写入数据的目的地
               boolean append:追加写开关
                true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据
                false:创建一个新文件,覆盖源文件
        写换行:写换行符号
            windows:\r\n
            linux:/n
            mac:/r
     */
    public static void demo03() throws IOException{
        FileOutputStream fos = new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt",true);
        for (int i = 1; i <=10 ; i++) {
            fos.write("你好".getBytes());
            fos.write("\r\n".getBytes());
        }
        fos.close();
    }

}

4.4字节输入流【InputStream】

   介绍:java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入 流的基本共性功能方法。
   基本共性功能方法
      public void close() :关闭此输入流并释放与此流相关联的任何系统资源
      public abstract int read() :从输入流读取数据的下一个字节
      public int read(byte[] b) :从输入流中读取一些字节数,并将它们存储到字节数组 b中
   小贴士:close方法,当完成流的操作时,必须调用此方法,释放系统资源

4.5FileInputStream类

   介绍:java.io.FileInputStream 类是文件输入流,从文件中读取字节
   构造方法
      FileInputStream(File file) :通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系 统中的 File对象 file命名
      FileInputStream(String name) :通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件 系统中的路径名 name命名
   读取字节数据
      1. 读取字节: read 方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回 -1
      2. 使用字节数组读取:read(byte[] b) ,每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读 取到末尾时,返回 -1
      小贴士:
         使用数组读取,每次读取多个字节,减少了系统间的IO操作次数,从而提高了读写的效率,建议开发中使 用字节流读取文字的时候可能会出现乱码和读取半个字单独问题这时候就需要使用字符流了。
代码:

package com.wyh.Io;

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

/**
 * @Deacription 字节输入流-FileInputStream类
 * @Author 王宇辉
 * @Date 2021/9/4 8:32
 * @Version 1.0
 **/
public class Demo09_InputStream {


    public static void main(String[] args) throws IOException {
        demo02();
    }

    /**
     * 字节输入流的基本使用
     *  读取数据的原理(硬盘-->内存)
     *         java程序-->JVM-->OS-->OS读取数据的方法-->读取文件
     *  字节输入流的使用步骤(重点):
     *         1.创建FileInputStream对象,构造方法中绑定要读取的数据源
     *         2.使用FileInputStream对象中的方法read,读取文件
     *         3.释放资源
     * @throws IOException
     */
    public static void demo01() throws IOException {
        //1.创建FileInputStream对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt");
        //2.使用FileInputStream对象中的方法read,读取文件
        //int read()读取文件中的一个字节并返回,读取到文件的末尾返回-1
        /*int len = fis.read();
        System.out.println(len);//97 a

        len = fis.read();
        System.out.println(len);// 98 b

        len = fis.read();
        System.out.println(len);//99 c

        len = fis.read();
        System.out.println(len);//-1

        len = fis.read();
        System.out.println(len);//-1*/

        /*
            发现以上读取文件是一个重复的过程,所以可以使用循环优化
            不知道文件中有多少字节,使用while循环
            while循环结束条件,读取到-1的时候结束

            布尔表达式(len = fis.read())!=-1
                1.fis.read():读取一个字节
                2.len = fis.read():把读取到的字节赋值给变量len
                3.(len = fis.read())!=-1:判断变量len是否不等于-1
         */
        int len = 0; //记录读取到的字节
        while((len = fis.read())!=-1){
            System.out.println(len);//abc
        }
        //3.释放资源
        fis.close();
    }

    /*字节输入流一次读取多个字节的方法:
            int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
        明确两件事情:
            1.方法的参数byte[]的作用?
                起到缓冲作用,存储每次读取到的多个字节
                数组的长度一把定义为1024(1kb)或者1024的整数倍
            2.方法的返回值int是什么?
                每次读取的有效字节个数

        String类的构造方法
            String(byte[] bytes) :把字节数组转换为字符串
            String(byte[] bytes, int offset, int length) 把字节数组的一部分转换为字符串 offset:数组的开始索引 length:转换的字节个数
     */
    public static void demo02() throws IOException{
        //创建FileInputStream对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt");
        //使用FileInputStream对象中的方法read读取文件
        //int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
        /*byte[] bytes = new byte[2];
        int len = fis.read(bytes);
        System.out.println(len);//2
        //System.out.println(Arrays.toString(bytes));//[65, 66]
        System.out.println(new String(bytes));//AB

        len = fis.read(bytes);
        System.out.println(len);//2
        System.out.println(new String(bytes));//CD

        len = fis.read(bytes);
        System.out.println(len);//1
        System.out.println(new String(bytes));//ED

        len = fis.read(bytes);
        System.out.println(len);//-1
        System.out.println(new String(bytes));//ED*/

        /*
            发现以上读取时一个重复的过程,可以使用循环优化
            不知道文件中有多少字节,所以使用while循环
            while循环结束的条件,读取到-1结束
         */
        byte[] bytes = new byte[1024];//存储读取到的多个字节
        int len = 0; //记录每次读取的有效字节个数
        while((len = fis.read(bytes))!=-1){
            //String(byte[] bytes, int offset, int length) 把字节数组的一部分转换为字符串 offset:数组的开始索引 length:转换的字节个数
            System.out.println(new String(bytes,0,len));
        }

        //释放资源
        fis.close();
    }
}

五,字符流

5.1字节流问题?

   当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为 一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文 件。

5.2字符输入流【Reader】

   介绍:java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。
   基本共性功能方法
      public void close() :关闭此流并释放与此流相关联的任何系统资源
      public int read() :从输入流读取一个字符
      public int read(char[] cbuf) : 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中

5.3FileReader类

   介绍:java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区
   小贴士:
      1. 字符编码:字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表idea中UTF-8
      2. 字节缓冲区:一个字节数组,用来临时存储字节数据
   构造方法
      FileReader(File file) : 创建一个新的 FileReader ,给定要读取的File对象
      FileReader(String fileName) :创建一个新的 FileReader ,给定要读取的文件的名称
   读取字符数据
      1. 读取字符:read 方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回 -1
      2. 使用字符数组读取:read(char[] cbuf) ,每次读取b的长度个字符到数组中,返回读取到的有效字符个数, 读取到末尾时,返回 -1
代码:

package com.wyh.Io;

import java.io.FileReader;
import java.io.IOException;

/*
    java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类

    共性的成员方法:
        int read() 读取单个字符并返回。
        int read(char[] cbuf)一次读取多个字符,将字符读入数组。
        void close() 关闭该流并释放与之关联的所有资源。

    java.io.FileReader extends InputStreamReader extends Reader
    FileReader:文件字符输入流
    作用:把硬盘文件中的数据以字符的方式读取到内存中

    构造方法:
        FileReader(String fileName)
        FileReader(File file)
        参数:读取文件的数据源
            String fileName:文件的路径
            File file:一个文件
        FileReader构造方法的作用:
            1.创建一个FileReader对象
            2.会把FileReader对象指向要读取的文件
    字符输入流的使用步骤:
        1.创建FileReader对象,构造方法中绑定要读取的数据源
        2.使用FileReader对象中的方法read读取文件
        3.释放资源
 */
public class Demo10_Reader {
    public static void main(String[] args) throws IOException {
        //1.创建FileReader对象,构造方法中绑定要读取的数据源
        FileReader fr = new FileReader("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt");
        //2.使用FileReader对象中的方法read读取文件
        //int read() 读取单个字符并返回。
        /*int len = 0;
        while((len = fr.read())!=-1){
            System.out.print((char)len);
        }*/

        //int read(char[] cbuf)一次读取多个字符,将字符读入数组。
        char[] cs = new char[1024];//存储读取到的多个字符
        int len = 0;//记录的是每次读取的有效字符个数
        while((len = fr.read(cs))!=-1){
            /*
                String类的构造方法
                String(char[] value) 把字符数组转换为字符串
                String(char[] value, int offset, int count) 把字符数组的一部分转换为字符串 offset数组的开始索引 count转换的个数
             */
            System.out.println(new String(cs,0,len));
        }
        //3.释放资源
        fr.close();
    }
}

5.4字符输出流【Writer】

   介绍:java.io.Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。
   基本共性功能方法
      void write(int c):写入单个字符
      void write(char[] cbuf):写入字符数组
      abstract void write(char[] cbuf, int off, int len):写入字符数组的某一部分,off数组的开始索引,len 写的字符个数
      void write(String str):写入字符串
      void write(String str, int off, int len):写入字符串的某一部分,off字符串的开始索引,len写的字符个 数
      void flush():刷新该流的缓冲
      void close():关闭此流,但要先刷新它

5.5FileWriter类

   介绍:关闭此流,但要先刷新它
   构造方法:
      FileWriter(File file) : 创建一个新的 FileWriter,给定要读取的File对象
      FileWriter(String fileName) :创建一个新的 FileWriter,给定要读取的文件的名称
   基本写出数据
      写出字符: write(int b) 方法,每次可以写出一个字符数据
   小贴士:
      1. 虽然参数为int类型四个字节,但是只会保留一个字符的信息写出
      2. 未调用close方法,数据只是保存到了缓冲区,并未写出到文件中
代码:

package com.wyh.Io;
import java.io.FileWriter;
import java.io.IOException;

/*
    java.io.Writer:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类

    共性的成员方法:
        - void write(int c) 写入单个字符。
        - void write(char[] cbuf)写入字符数组。
        - abstract  void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
        - void write(String str)写入字符串。
        - void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
        - void flush()刷新该流的缓冲。
        - void close() 关闭此流,但要先刷新它。

    java.io.FileWriter extends OutputStreamWriter extends Writer
    FileWriter:文件字符输出流
    作用:把内存中字符数据写入到文件中

    构造方法:
        FileWriter(File file)根据给定的 File 对象构造一个 FileWriter 对象。
        FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。
        参数:写入数据的目的地
            String fileName:文件的路径
            File file:是一个文件
        构造方法的作用:
            1.会创建一个FileWriter对象
            2.会根据构造方法中传递的文件/文件的路径,创建文件
            3.会把FileWriter对象指向创建好的文件

    字符输出流的使用步骤(重点):
        1.创建FileWriter对象,构造方法中绑定要写入数据的目的地
        2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
        3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中
        4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
 */
public class Demo11_Writer {
    public static void main(String[] args) throws IOException {
        demo02();
    }


    /**
     * 基本使用
     * @throws IOException
     */
    public static void demo01() throws IOException{
        //1.创建FileWriter对象,构造方法中绑定要写入数据的目的地
        FileWriter fw = new FileWriter("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\d.txt");
        //2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
        //void write(int c) 写入单个字符。
        fw.write(97);
        //3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中
        fw.flush();
        //4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
        fw.close();
    }


    /*
      字符输出流写数据的其他方法
            - void write(char[] cbuf)写入字符数组。
            - abstract  void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
            - void write(String str)写入字符串。
            - void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
     */
    public static void demo02() throws IOException{
        FileWriter fw = new FileWriter("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\d.txt");
        char[] cs = {'a','b','c','d','e'};
        //void write(char[] cbuf)写入字符数组。
        fw.write(cs);//abcde

        //void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
        fw.write(cs,1,3);//bcd

        //void write(String str)写入字符串。
        fw.write("程序员");

        //void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
        fw.write("开课吧的程序员",2,3);

        fw.close();
    }

    /*
        续写和换行
        续写,追加写:使用两个参数的构造方法
            FileWriter(String fileName, boolean append)
            FileWriter(File file, boolean append)
            参数:
                String fileName,File file:写入数据的目的地
                boolean append:续写开关 true:不会创建新的文件覆盖源文件,可以续写; false:创建新的文件覆盖源文件
         换行:换行符号
            windows:\r\n
            linux:/n
            mac:/r
     */
    public static void demo03() throws IOException{
        FileWriter fw = new FileWriter("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\g.txt",true);
        for (int i = 0; i <10 ; i++) {
            fw.write("HelloWorld"+i+"\r\n");
        }
        fw.close();
    }
}

   关闭和刷新
      为什么?
         因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush方法了。
         flush :刷新缓冲区,流对象可以继续使用
         close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了
         小贴士:
            即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源
代码:

package com.wyh.Io;
import java.io.FileWriter;
import java.io.IOException;

/*
    flush方法和close方法的区别
        - flush :刷新缓冲区,流对象可以继续使用。
        - close:  先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
 */
public class Demo12_CloseAndFlush {
    public static void main(String[] args) throws IOException {
        //1.创建FileWriter对象,构造方法中绑定要写入数据的目的地
        FileWriter fw = new FileWriter("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\e.txt");
        //2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
        //void write(int c) 写入单个字符。
        fw.write(97);
        //3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中
        fw.flush();
        //刷新之后流可以继续使用
        fw.write(98);

        //4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
        fw.close();
        //close方法之后流已经关闭了,已经从内存中消失了,流就不能再使用了
        fw.write(99);//IOException: Stream closed
    }
}

   写出其他数据
      1. 写出字符数组 :write(char[] cbuf) 和 write(char[] cbuf, int off, int len) ,每次可以写出字符数 组中的数据,用法类似FileOutputStream
      2. 写出字符串:write(String str) 和 write(String str, int off, int len) ,每次可以写出字符串中的 数据,更为方便
      3. 续写和换行:操作类似于FileOutputStream
      小贴士:字符流,只能操作文本文件,不能操作图片,视频等非文本文件。 当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流
小练习:文件复印

package com.wyh.Io;

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

/**
 * @Deacription 文件复制练习:一读一写
 *     明确:(这个地点文件随便)
 *         数据源: c:\\1.jpg
 *         数据的目的地: d:\\1.jpg
 *
 *     文件复制的步骤:
 *         1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
 *         2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
 *         3.使用字节输入流对象中的方法read读取文件
 *         4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
 *         5.释放资源
 * @Author 王宇辉
 * @Date 2021/9/4 13:43
 * @Version 1.0
 **/
public class Task02 {
    public static void main(String[] args) throws IOException {
        long s = System.currentTimeMillis();
        //1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("c:\\王宇辉.jpg");
        //2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
        FileOutputStream fos = new FileOutputStream("d:\\王宇辉.jpg");

        //一次读取一个字节写入一个字节的方式
        //3.使用字节输入流对象中的方法read读取文件
        /*int len = 0;
        while((len = fis.read())!=-1){
            //4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
            fos.write(len);
        }*/

        //使用数组缓冲读取多个字节,写入多个字节
        byte[] bytes = new byte[1024];
        //3.使用字节输入流对象中的方法read读取文件
        int len = 0;//每次读取的有效字节个数
        while((len = fis.read(bytes))!=-1){
            //4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
            fos.write(bytes,0,len);
        }

        //5.释放资源(先关写的,后关闭读的;如果写完了,肯定读取完毕了)
        fos.close();
        fis.close();
        long e = System.currentTimeMillis();
        System.out.println("复制文件共耗时:"+(e-s)+"毫秒");
    }
}

六,转换流

6.1什么是字符编码?

   按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照 某种规则解析显示出来,称为解码 。字符编码 Character Encoding :就是一套自然语言的字符与二进制数之间的对应规则

6.2字符集

   什么是字符集 Charset :
      也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符 号、数字等
   字符集图解:

6.3InputStreamReader类

   是什么?
      转换流 java.io.InputStreamReader ,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定 的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
   构造方法
      InputStreamReader(InputStream in) :创建一个使用默认字符集的字符流
      InputStreamReader(InputStream in, String charsetName) :创建一个指定字符集的字符流
   构造举例:
      InputStreamReader isr = new InputStreamReader(new FileInputStream(“in.txt”));
      InputStreamReader isr2 = new InputStreamReader(new FileInputStream(“in.txt”) , “GBK”);
代码:

package com.wyh.ZhuanHuanLiu;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/*
    java.io.InputStreamReader extends Reader
    InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。(解码:把看不懂的变成能看懂的)

    继承自父类的共性成员方法:
        int read() 读取单个字符并返回。
        int read(char[] cbuf)一次读取多个字符,将字符读入数组。
        void close() 关闭该流并释放与之关联的所有资源。
    构造方法:
        InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
        InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。
        参数:
            InputStream in:字节输入流,用来读取文件中保存的字节
            String charsetName:指定的编码表名称,不区分大小写,可以是utf-8/UTF-8,gbk/GBK,...不指定默认使用UTF-8
     使用步骤:
        1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
        2.使用InputStreamReader对象中的方法read读取文件
        3.释放资源
     注意事项:
        构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
 */
public class Demo14_InputStreamReader {
    public static void main(String[] args) throws IOException {
        //read_utf_8();
        read_gbk();
    }

    /*
        使用InputStreamReader读取GBK格式的文件
     */
    private static void read_gbk() throws IOException {
        //1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
        //InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\gbk.txt"),"UTF-8");//???
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\gbk.txt"),"GBK");//你好

        //2.使用InputStreamReader对象中的方法read读取文件
        int len = 0;
        while((len = isr.read())!=-1){
            System.out.println((char)len);
        }
        //3.释放资源
        isr.close();
    }

    /*
        使用InputStreamReader读取UTF-8格式的文件
     */
    private static void read_utf_8() throws IOException {
        //1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
        //InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\utf_8.txt"),"UTF-8");
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\utf_8.txt"));//不指定默认使用UTF-8
        //2.使用InputStreamReader对象中的方法read读取文件
        int len = 0;
        while((len = isr.read())!=-1){
            System.out.println((char)len);
        }
        //3.释放资源
        isr.close();
    }
}

6.4OutputStreamWriter类

   是什么?
      转换流 java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符 编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
   构造方法
      OutputStreamWriter(OutputStream in) :创建一个使用默认字符集的字符流
      OutputStreamWriter(OutputStream in, String charsetName) :创建一个指定字符集的字符流
   构造举例
      OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream(“out.txt”));
      OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream(“out.txt”) , “GBK”);
代码:

package com.wyh.ZhuanHuanLiu;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/*
    java.io.OutputStreamWriter extends Writer
    OutputStreamWriter: 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。(编码:把能看懂的变成看不懂)

    继续自父类的共性成员方法:
        - void write(int c) 写入单个字符。
        - void write(char[] cbuf)写入字符数组。
        - abstract  void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
        - void write(String str)写入字符串。
        - void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
        - void flush()刷新该流的缓冲。
        - void close() 关闭此流,但要先刷新它。
    构造方法:
        OutputStreamWriter(OutputStream out)创建使用默认字符编码的 OutputStreamWriter。
        OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter。
        参数:
            OutputStream out:字节输出流,可以用来写转换之后的字节到文件中
            String charsetName:指定的编码表名称,不区分大小写,可以是utf-8/UTF-8,gbk/GBK,...不指定默认使用UTF-8
    使用步骤:
        1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称
        2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)
        3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
        4.释放资源
 */
public class Demo13_OutputStreamWriter {
    public static void main(String[] args) throws IOException {
        write_utf_8();
        //write_gbk();
    }

    /*
       使用转换流OutputStreamWriter写GBK格式的文件
    */
    private static void write_gbk() throws IOException {
        //1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\gbk.txt"),"GBK");
        //2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)
        osw.write("你好");
        //3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
        osw.flush();
        //4.释放资源
        osw.close();
    }

    /*
        使用转换流OutputStreamWriter写UTF-8格式的文件
     */
    private static void write_utf_8() throws IOException {
        //1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\utf_8.txt"),"utf-8");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\utf_8.txt"));//不指定默认使用UTF-8
        //2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)
        osw.write("你好");
        //3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
        osw.flush();
        //4.释放资源
        osw.close();
    }

}

6.5转换流理解图解:转换流是字节与字符间的桥梁

在这里插入图片描述

6.6练习:转换文件编码

将GBK编码的文本文件,转换为UTF-8编码的文本文件
代码:

package com.wyh.ZhuanHuanLiu;
import java.io.*;

/*
    练习:转换文件编码
        将GBK编码的文本文件,转换为UTF-8编码的文本文件。

    分析:
        1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBK
        2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8
        3.使用InputStreamReader对象中的方法read读取文件
        4.使用OutputStreamWriter对象中的方法write,把读取的数据写入到文件中
        5.释放资源
 */
public class Task03 {
    public static void main(String[] args) throws IOException {
        //1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBK
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\gbk.txt"),"GBK");
        //2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\utf_8.txt"),"UTF-8");
        //3.使用InputStreamReader对象中的方法read读取文件
        int len = 0;
        while((len = isr.read())!=-1){
            //4.使用OutputStreamWriter对象中的方法write,把读取的数据写入到文件中
            osw.write(len);
        }
        //5.释放资源
        osw.close();
        isr.close();
    }
}

七,打印流与缓存流

   缓冲流和打印流都是为了 提高输入输出流的效率 而出现的

7.1打印流是什么?

   在控制台,我们经常使用System.out.print(),System.out.println(),System.out.printf()这样的函数,点开out的源码,我们可以发现这个静态变量public static final PrintStream out = null;控制台的输出,其实是在调用PrintStream中的方法,这个类不仅可以把数据输出到控制台,也可以把数据输出到文件。
   PrintStream 打印字节流,PrintWriter打印字符流。他们的用法完全一样,但是PrintWriter其实是缓冲流,需要flush()冲马桶,而PrintStream则无缓存,直接打印。PrintStream --> FilterOutputStream–> OutputStreamPrintWriter --> Writer
   以PrintStream为例子来
      说明打印流,除了一系列的print,pirntf,println方法,其他用法和OutputStream输出流里定义的方法完全一致。但是既然可以打印,一般就不append()了吧。
代码:

package com.wyh.DaYinYuHuanCun;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;

/**
 * @Deacription 打印流
 * @Author 王宇辉
 * @Date 2021/9/4 14:45
 * @Version 1.0
 **/
public class Demo15_DaYin {
    public static void main(String[] args) throws FileNotFoundException {
        PrintWriter pw = new PrintWriter("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\a.txt");
        pw.write(54);
        pw.println("sm");
        pw.flush();
        pw.close();
        PrintStream ps = new PrintStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\a.txt");
        ps.println("锄禾日当午,清明上河图");
        ps.close();

        PrintWriter pl = new PrintWriter(new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt"));
        pl.println("床前明月光,疑是地上霜");
        pl.flush();
        pl.close();
    }
}

7.2缓冲流

   在编程或者刷题的时候,我们经常会从控制台读取信息,比如Scanner input = newScanner(System.in);,如果我们查看in的源代码,会发现它的实现是public static final InputStream in = null;它其实是一个输入流,System.in说明从控制台读数据。
      如果我们经常用java刷题,一定见过这个声明:BufferedReader br = new BufferedReader(new InputStreamReader(System.in));这个br同样可以从控制台接收输入,而且将字节流转换为字符流,但是速度会快很多。通常可以解决java速度太慢运行超时的问题。
      使用BufferedReader读取字符流时,可以显著增加读取效率,并且提供了额外的readLine()方法,一次可读一行。看一段代码,readLine()方法读完时会返回null,BufferedReader的构造方法正需要接收一个Reader,并可以在适当的时候指定缓存区的大小size(默认8192)
代码:

package com.wyh.DaYinYuHuanCun;

import java.io.*;

/**
 * @Deacription 缓存流
 * @Author 王宇辉
 * @Date 2021/9/4 14:46
 * @Version 1.0
 **/
public class Demo16_HuanCun {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt"));
        while(true){
            String s = br.readLine();
            if(s == null) break;
            System.out.println(s);
        }
        br.close();
    }
}

7.3其他:

使用 PrintWriter的话要刷新管道
字节流可以转成打印流,方法同转换流。

7.4收集Java异常日志

创建文档bug.txt,来收集异常。即每次抛出异常时,将异常写入文档中。

代码:

package com.wyh;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Deacription:收集异常日志(Java)
 * @Author 王宇辉
 * @Date 2021/9/4 15:03
 * @Version 1.0
 **/
public class Demo17_YiChangRiZhi {
    public static void main(String[] args) throws FileNotFoundException {
        try {
            String s = null;
            s.toString();
        }catch(Exception e){
            PrintWriter pw = new PrintWriter("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\bug.txt");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            pw.println(sdf.format(new Date()));
            e.printStackTrace(pw);
            pw.close();
        }
    }
}

八,属性集

8.1概述:

   java.util.Properties 继承于 Hashtable ,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其 对应值都是一个字符串。
   该类也被许多Java类使用,比如获取系统属性时, System.getProperties 方法就是返回 一个 Properties 对象。

8.2Properties类

   构造方法
      public Properties() :创建一个空的属性列表
   基本的存储方法
      public Object setProperty(String key, String value) : 保存一对属性
      public String getProperty(String key) :使用此属性列表中指定的键搜索属性值
      public Set stringPropertyNames() :所有键的名称的集合
   与流相关的方法
      public void load(InputStream inStream) :从字节输入流中读取键值对
      小贴士:文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔
代码:

package com.wyh;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

/*
    java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>
    Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。
    Properties集合是一个唯一和IO流相结合的集合
        可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
        可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用

    属性列表中每个键及其对应值都是一个字符串。
        Properties集合是一个双列集合,key和value默认都是字符串
 */
class Demo18_Properties {
    public static void main(String[] args) throws IOException {
        show02();
    }
    /*
            可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
            void load(InputStream inStream)
            void load(Reader reader)
            参数:
                InputStream inStream:字节输入流,不能读取含有中文的键值对
                Reader reader:字符输入流,能读取含有中文的键值对
            使用步骤:
                1.创建Properties集合对象
                2.使用Properties集合对象中的方法load读取保存键值对的文件
                3.遍历Properties集合
            注意:
                1.存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
                2.存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
                3.存储键值对的文件中,键与值默认都是字符串,不用再加引号
         */
    private static void show03() throws IOException {
        //1.创建Properties集合对象
        Properties prop = new Properties();
        //2.使用Properties集合对象中的方法load读取保存键值对的文件
        prop.load(new FileReader("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\prop.txt"));
        //prop.load(new FileInputStream("09_IOAndProperties\\prop.txt"));
        //3.遍历Properties集合
        Set<String> set = prop.stringPropertyNames();
        for (String key : set) {
            String value = prop.getProperty(key);
            System.out.println(key+"="+value);
        }
    }
    /*
        可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
        void store(OutputStream out, String comments)
        void store(Writer writer, String comments)
        参数:
            OutputStream out:字节输出流,不能写入中文
            Writer writer:字符输出流,可以写中文
            String comments:注释,用来解释说明保存的文件是做什么用的
                    不能使用中文,会产生乱码,默认是Unicode编码
                    一般使用""空字符串

        使用步骤:
            1.创建Properties集合对象,添加数据
            2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
            3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
            4.释放资源
     */
    private static void show02() throws IOException {
        //1.创建Properties集合对象,添加数据
        Properties prop = new Properties();
        prop.setProperty("赵丽颖","168");
        prop.setProperty("迪丽热巴","165");
        prop.setProperty("古力娜扎","160");

        //2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
        FileWriter fw = new FileWriter("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\prop.txt");

        //3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
        prop.store(fw,"save data");

        //4.释放资源
        fw.close();

        //prop.store(new FileOutputStream("09_IOAndProperties\\prop2.txt"),"");
    }

    /*
        使用Properties集合存储数据,遍历取出Properties集合中的数据
        Properties集合是一个双列集合,key和value默认都是字符串
        Properties集合有一些操作字符串的特有方法
            Object setProperty(String key, String value) 调用 Hashtable 的方法 put。
            String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get(key)方法
            Set<String> stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
     */
    private static void show01() {
        //创建Properties集合对象
        Properties prop = new Properties();
        //使用setProperty往集合中添加数据
        prop.setProperty("赵丽颖","168");
        prop.setProperty("迪丽热巴","165");
        prop.setProperty("古力娜扎","160");
        //prop.put(1,true);

        //使用stringPropertyNames把Properties集合中的键取出,存储到一个Set集合中
        Set<String> set = prop.stringPropertyNames();

        //遍历Set集合,取出Properties集合的每一个键
        for (String key : set) {
            //使用getProperty方法通过key获取value
            String value = prop.getProperty(key);
            System.out.println(key+"="+value);
        }
    }
}

九,序列化(不熟)

9.1是什么?

   序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组。 为什么要把Java对象序列化呢?因为序列化后可以把byte[]保存到文件中,或者把byte[]通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。 有序列化,就有反序列化,即把一个二进制内容(也就是byte[]数组)变回Java对象。有了反序列化,保存到文件中的byte[]数组又可以“变回”Java对象,或者从网络上读取byte[]并把它“变回”Java对象。核心作用就是对象状态的保存和重建。(整个过程核心点就是字节流中所保存的对象状态及描述信息)

9.2图解:在这里插入图片描述### 9.3json/xml的数据传递:

   在数据传输(也可称为网络传输)前,先通过序列化工具类将Java对象序列化为json/xml文件。
   在数据传输(也可称为网络传输)后,再将json/xml文件反序列化为对应语言的对象

9.4序列化优点:

   ①将对象转为字节流存储到硬盘上,当JVM停机的话,字节流还会在硬盘上默默等待,等待下一次JVM的启动,把序列化的对象,通过反序列化为原来的对象,并且序列化的二进制序列能够减少存储空间(永久性保存对象)。
   ②序列化成字节流形式的对象可以进行网络传输(二进制形式),方便了网络传输。
   ③通过序列化可以在进程间传递对象。

9.5Java实现序列化和反序列化的过程

   1、实现序列化的必备要求:
      只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常)
   2、JDK中序列化和反序列化的API:
      ①java.io.ObjectInputStream:对象输入流。
         该类的readObject()方法从输入流中读取字节序列,然后将字节序列反序列化为一个对象并返回。
       ②java.io.ObjectOutputStream:对象输出流。
         该类的writeObject(Object obj)方法将将传入的obj对象进行序列化,把得到的字节序列写入到目标输出流中进行输出。
   序列化和反序列化代码示例
   3,部分属性的序列化 (看文档)

9.6序列化和反序列化的注意点:

   ①序列化时,只对对象的状态进行保存,而不管对象的方法;
   ②当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
   ③当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
   ④并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:
      安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;
      资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;
   ⑤声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。
   ⑦Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的;
代码:

package com.wyh.XuLieHua;

import java.io.Serializable;
import java.util.List;

/**
 * @Deacription 学生实体类
 * @Author 王宇辉
 * @Date 2021/9/4 21:03
 * @Version 1.0
 **/
public class Student implements Serializable {
    /**
     * 学号
     */
    private String stuNum;
    /**
     * 姓名
     */
    private String stuName;
    /**
     * 教师姓名:一个学生可以有多个老师
     */
    private List<String> teacherList;
    //无参数构造方法
    public Student() {
    }
    //全参构造方法
    public Student(String stuNum, String stuName, List<String> teacherList) {
        this.stuNum = stuNum;
        this.stuName = stuName;
        this.teacherList = teacherList;
    }
    @Override
    public String toString() {
        return "Student{" +
                "stuNum='" + stuNum + '\'' +
        ", stuName='" + stuName + '\'' +
                ", teacherList=" + teacherList +
                '}';
    }
    public String getStuNum() {
        return stuNum;
    }
    public void setStuNum(String stuNum) {
        this.stuNum = stuNum;
    }
    public String getStuName() {
        return stuName;
    }
    public void setStuName(String stuName) {
        this.stuName = stuName;
    }
    public List<String> getTeacherList() {
        return teacherList;
    }
    public void setTeacherList(List<String> teacherList) {
        this.teacherList = teacherList;
    }

}
package com.wyh.XuLieHua;

import java.io.*;

/**
 * @Deacription 序列化和反序列化的工具类
 * @Author 王宇辉
 * @Date 2021/9/4 21:07
 * @Version 1.0
 **/
public class MySerializeUtil {
    /**
     * 将对象序列化到指定文件中
     * @param obj
     * @param fileName
     */
    public static void mySerialize(Object obj,String fileName) throws IOException {
        OutputStream out=new FileOutputStream(fileName);
        ObjectOutputStream objOut=new ObjectOutputStream(out);
        objOut.writeObject(obj);
        objOut.close();
    }
    /**
     * 从指定文件中反序列化对象
     * @param fileName
     * @return
     */
    public static Object myDeserialize(String fileName) throws IOException,ClassNotFoundException {
        InputStream in=new FileInputStream(fileName);
        ObjectInputStream objIn=new ObjectInputStream(in);
        Object obj=objIn.readObject();
        return obj;
    }
}
package com.wyh.XuLieHua;

import java.util.ArrayList;
import java.util.List;

/**
 * @Deacription 测试类
 * @Author 王宇辉
 * @Date 2021/9/4 21:06
 * @Version 1.0
 **/
public class MainTest {
    public static void main(String[] args) {
        List<String> teacherList=new ArrayList<>();
        teacherList.add("空空道人");
        teacherList.add("贾代儒");
        Student stu1=new Student("1001", "贾宝玉", teacherList);
        System.out.println("原始对象:"+stu1);
        String fileName="D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\a.txt";
        try {
            //对象序列化
            MySerializeUtil.mySerialize(stu1, fileName);
            System.out.println("序列化原始对象完成!OK!");
             //对象的反序列化
            Object obj=MySerializeUtil.myDeserialize(fileName);
            if(obj instanceof Student){
                Student stuNew= (Student) obj;
                System.out.println("反序列化之后的对象:"+stuNew);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
package com.wyh.XuLieHua;

import java.io.*;

/**
 * @Deacription 序列化
 * @Author 王宇辉
 * @Date 2021/9/4 15:58
 * @Version 1.0
 **/
public class Demo19_XuLieHua {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 序列化:对象变字节
        /*Book b = new Book("金苹果","金苹果的种植过程");
        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\bug.txt"));
        os.writeObject(b);
        os.close();*/

        // 反序列化:字节变对象
        ObjectInputStream os = new ObjectInputStream(new FileInputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\bug.txt"));
        Book o =(Book) os.readObject();
        System.out.println(o);
    }

    static class Book implements Serializable{
        private String name;
        private String info;

        public String getName() {
            return name;
        }

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

        public String getInfo() {
            return info;
        }

        public void setInfo(String info) {
            this.info = info;
        }

        public Book() {
        }

        public Book(String name, String info) {
            this.name = name;
            this.info = info;
        }

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

十,IO异常的处理

10.1JDK7前处理

   在jdk1.7之前使用trycatchfinally处理流中的异常
   格式:
      try{
      可能会产出异常的代码
      }catch(异常类变量变量名){
      异常的处理逻辑
      }finally{
      一定会指定的代码
      资源释放
      }
代码:

package com.wyh.IOYiChang;
import java.io.FileWriter;
import java.io.IOException;

/*
    在jdk1.7之前使用try catch finally 处理流中的异常
    格式:
        try{
            可能会产出异常的代码
        }catch(异常类变量 变量名){
            异常的处理逻辑
        }finally{
            一定会指定的代码
            资源释放
        }
 */
public class Demo20_TryCatch {
    public static void main(String[] args) {
        //提高变量fw的作用域,让finally可以使用
        //变量在定义的时候,可以没有值,但是使用的时候必须有值
        //fw = new FileWriter("09_IOAndProperties\\g.txt",true); 执行失败,fw没有值,fw.close会报错
        FileWriter fw = null;
        try{
            //可能会产出异常的代码
            fw = new FileWriter("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\b.txt",true);
            for (int i = 0; i <10 ; i++) {
                fw.write("HelloWorld"+i+"\r\n");
            }
        }catch(IOException e){
            //异常的处理逻辑
            System.out.println(e);
        }finally {
            //一定会指定的代码
            //创建对象失败了,fw的默认值就是null,null是不能调用方法的,会抛出NullPointerException,需要增加一个判断,不是null在把资源释放
            if(fw!=null){
                try {
                    //fw.close方法声明抛出了IOException异常对象,所以我们就的处理这个异常对象,要么throws,要么try catch
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

10.2JDK7的处理

   JDK7的新特性
      在try的后边可以增加一个(),在括号中可以定义流对象那么这个流对象的作用域就在try中有效try中的代码执行完毕,会自动把流对象释放,不用写finally
   格式:
      try(定义流对象;定义流对象…){
      可能会产出异常的代码
      }catch(异常类变量变量名){
      异常的处理逻辑
      }
代码:

package com.wyh.IOYiChang;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/*
    JDK7的新特性
    在try的后边可以增加一个(),在括号中可以定义流对象
    那么这个流对象的作用域就在try中有效
    try中的代码执行完毕,会自动把流对象释放,不用写finally
    格式:
        try(定义流对象;定义流对象....){
            可能会产出异常的代码
        }catch(异常类变量 变量名){
            异常的处理逻辑
        }
 */
public class Demo21_JDK7 {
    public static void main(String[] args) {
        try(//1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
            FileInputStream fis = new FileInputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt");
            //2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
            FileOutputStream fos = new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\b.txt");){

            //可能会产出异常的代码
            //一次读取一个字节写入一个字节的方式
            //3.使用字节输入流对象中的方法read读取文件
            int len = 0;
            while((len = fis.read())!=-1){
                //4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
                fos.write(len);
            }
        }catch (IOException e){
            //异常的处理逻辑
            System.out.println(e);
        }
    }
}

10.3JDK9的改进

   JDK9新特性
      try的前边可以定义流对象在try后边的()中可以直接引入流对象的名称(变量名)在try代码执行完毕之后,流对象也可以释放掉,不用写finally
   格式:
      Aa=newA();
      Bb=newB();
      try(a,b){
      可能会产出异常的代码
      }catch(异常类变量变量名){
      异常的处理逻辑
      }
   提示:创建的对象必须要实现Closeable
代码:

package com.wyh.IOYiChang;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/*
    JDK9新特性
    try的前边可以定义流对象
    在try后边的()中可以直接引入流对象的名称(变量名)
    在try代码执行完毕之后,流对象也可以释放掉,不用写finally
    格式:
        A a = new A();
        B b = new B();
        try(a,b){
            可能会产出异常的代码
        }catch(异常类变量 变量名){
            异常的处理逻辑
        }
 */
public class Demo22_JDK9 {
    public static void main(String[] args) throws IOException {
        //1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\c.txt");
        //2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
        FileOutputStream fos = new FileOutputStream("D:\\eclipse-workspace\\C_XX_HeXinLeiKu\\c_XX_IO\\IO\\a.txt");
        CloseDemo d = new CloseDemo();
        try(fis;fos;d){
            //一次读取一个字节写入一个字节的方式
            //3.使用字节输入流对象中的方法read读取文件
            int len = 0;
            while((len = fis.read())!=-1){
                //4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
                fos.write(len);
            }
        }catch (IOException e){
            System.out.println(e);
        }
        //fos.write(1);//Stream Closed
    }

    // 提示:创建的对象必须要实现Closeable
    static class CloseDemo implements Closeable {
        @Override
        public void close() throws IOException {
            System.out.println("Close方法被调用了");
        }
    }
}

十一,综合练习

这个练习需要费点时间,以后再说吧。

参考:距离记笔记的时候过了一段时间,如果我的笔记有明显借鉴了您的内容,请见谅。(我记忆力很差的,当初写笔记的时候,参考文档记录的可能不全)
不知道是什么的参考:
https://www.cnblogs.com/zhangminghui/p/4484579.html
资料下载链接(笔记+代码+其他):百度网盘
链接:https://pan.baidu.com/s/1Q8SGVvJKloeeovT1iognfg
提取码:1111
感谢阅读,祝你从此一帆风顺。