02_Java语音进阶||day09_IO概念、字节流、字符流、IO异常的处理、属性集

第一章 IO概念

1.1 什么是IO

  1. Java中I/O操作主要是指使用java.io包下的内容,进行输入,输出操作。
    • 输入也叫做:读取数据
    • 输出也叫做:写入数据
  2. 内存(RAM),硬盘(ROM)

1.2 IO的分类

1.3 IO的流向说明图解

  1. 根据数据的流向分为:
    • 输入流
    • 输出流
  2. 根据数据的类型分为:
    • 字节流
    • 字符流

1.4 顶级父类们

1.5 总结

  1. I/O流介绍:
    • I:input 输入(读取)
      • 输入:把硬盘中的数据,读取到内存中使用
    • O:output 输出(写入)
      • 输出:把内存中的数据,写入到硬盘中保存
    • 流:数据(字符,字节
      • 1个字符 = 2个字节
      • 1个字节 = 8个二进制
    • 因为流中数据分为(字符,字节)所以有:
      • 字节输入流
      • 字节输出流
      • 字符输入流
      • 字符输出流

第二章 字节流

2.1 一切皆为字节

2.2 字节输出流_OutputStream类&FileOutputStream类介绍

  1. java.io.OutputStream:字节输出流
    • 抽象类是表示输出字节流的所有类的超类。
  2. 定义了一些子类共性的成员方法:
    • 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) :将指定的字节输出流。(1字节)
  3. java.io.FileOutputStream extends OutputStream
    • FileOutputStream:文件字节输出流
  4. 作用:把内存中的数据写入到硬盘的文件中
  5. 构造方法:
    • FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流。
    • FileOutputStream(File file) :创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
    1. 参数:写入数据的目的
      • String name:目的地是一个文件的路径
      • File file:目的地是一个文件
    2. 构造方法的作用:
      1. 创建一个FileOutputStream对象
      2. 根据构造方法中传递的文件/文件路径,创建一个空的文件
      3. 会把FileOutputStream对象指向创建好的文件

2.3 字节输出流写入数据到文件

  1. 写入数据的原理(内存–>硬盘)
    • java程序–>JVM(java虚拟机)–>OS(操作系统)–>OS调用写数据的方法–>把数据写入到文件中
  2. 字节输出流的使用步骤【重点】:
    1. 创建一个FileOutputStream对象,构造方法中传递写入数据的目的地(创建一个空的文件)
    2. 调用FileOutputStream对象中的方法write,把数据写入到文件中
    3. 释放资源[close方法](流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)
  3. 三个步骤都会报出异常解决如下:
    1. 创建FileOutputStream对象会抛出–>io.FileNotFoundException
    2. write和close方法会抛出–>io.IOException
    3. 因为FileNotFoundException是IOException的子类
    4. 所以直接抛出IOException异常即可。(throws IOException)
    import java.io.FileOutputStream;
    import java.io.IOException;

    public class Demo01OutputStream {
        public static void main(String[] args) throws IOException {
            //1. ==创建==一个==FileOutputStream对象==,==构造方法中==传递==写入数据的目的地==(创建一个空的文件)
            //写入到day09路径下
            FileOutputStream fos = new FileOutputStream("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\a.txt");
            //2. ==调用==FileOutputStream对象中的==方法write==,==把数据写入到文件中==
            //* public abstract void ==write==(int b) :将指定的字节输出流。
            fos.write(97);
            //3. ==释放资源==(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)
            fos.close();
        }
    }

2.4 文件存储的原理和记事本打开文件的原理

2.5 字节输出流写多个字节的方法

  1. public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
    • 一次写多个字节:
      • 如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表
      • 如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表(GBK)
  2. public void write(byte[] b, int off, int len) :把字节数组的一部分写入到文件中
    • int off:数组的开始索引
    • int len:写几个字节
  3. 写入字符的方法:可以使用String类中的方法把字符串,转换为字节数组
    • byte[] getBytes() 把字符串转换为字节数组
    • 注:UTF-8中3个字节为一个中文,GBK是两个字节【重点】
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Arrays;

    public class Demo02OutputStream {
        public static void main(String[] args) throws IOException {
            //创建FileOutputStream对象,构造方法中绑定要写入数据的目的地
            FileOutputStream fos = new FileOutputStream(new File("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\b.txt"));
            //调用FileOutputStream对象中的方法write,把数据写入到文件中
            //在文件中显示100,写几个字节(3个)
            fos.write(49);
            fos.write(48);
            fos.write(48);
    
            //public void write(byte[] b)
            //如果写的==第一个字节是正数==(0-127),==那么显示的时候会查询ASCII表==
            byte[] bytes = {65, 66, 67, 68, 69};  //ABCDE
            //如果写的==第一个字节是负数==,那==第一个字节会和第二个字节,两个字节组成一个中文显示==,查询系统默认码表(GBK)
            //byte[] bytes = {-65, -66, -67, 68, 69}; //烤紻E
            //fos.write(bytes);
    
            /*
            public void write(byte[] b, int off, int len) :把字节数组的一部分写入到文件中
                    * int off:==数组的开始索引==
                    * int len:==写几个字节==
    
             */
            fos.write(bytes, 1, 2); //BC
    
            //byte[] ==getBytes==()
            byte[] bytes1 = "你好".getBytes();
            System.out.println(Arrays.toString(bytes1));    //[-28, -67, -96, -27, -91, -67]
            fos.write(bytes1);  //你好
    
    
            //释放资源
            fos.close();
        }
    }

2.6 字节输出流的续写和换行(前面的方式再次运行会覆盖)

  1. 追加写/续写【重点】:使用两个参数的构造方法
    • FileOutputStream(String name, boolean append)创建一个向具有指定 name 的文件中写入数据的输出文件流。
    • FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
    1. 参数:
      • String name,File file:写入数据的目的地
      • boolean append:追加写开关
        • true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据
        • false:创建一个新文件,覆盖源文件
  2. 写换行:写换行符号【重点】(这个也是属于字符串:getBytes()来转为字节数组)
    • windows:\r\n
      • 一起写分开写都可以
    • linux:/n
    • mac:/r
    import java.io.FileOutputStream;
    import java.io.IOException;

    public class Demo03OutputStream {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\c.txt", true);
    
            for(int i = 0; i <= 2; i++){
                fos.write("你好".getBytes());
                fos.write("\r\n".getBytes());
            }
            fos.close();
        }
    }
    
    //结果:
        
    你好
    你好
    你好

2.7 字节输入流_InputStream类&FileInputStream类介绍

  1. java.io.InputStream:字节输入流
    • 抽象类是表示字节输入流的所有类的超类。
  2. 定义了所有子类共性的方法:
    • int read():从输入流中读取数据的下一个字节。
      • 读取文件中的一个字节并返回,读取到文件的末尾返回-1
      • 每次读取一个字节指针向后移一位
    • int read(byte[] b):从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
    • void close():关闭此输入流并释放与该流关联的所有系统资源
  3. java.io.FileInputStream extends InputStream
    • FileInputStream:文件字节输入流
  4. 作用:把硬盘文件中的数据,读取到内存中使用
  5. 构造方法:
    • FileInputStream(String name)
    • FileInputStream(File file)
    1. 参数:读取文件的数据源
      • String name:文件的路径
      • File file:文件
    2. 构造方法的作用:
      1. 会创建一个FileInputStream对象
      2. 会把FileInputStream对象指向构造方法中要读取的文件

2.8 字节输入流读取字节数据

  1. 读取数据的原理(硬盘–>内存)

    • java程序–>JVM–>OS–>OS读取数据的方法–>读取文件
  2. 字节输入流的使用步骤【重点】

    1. 创建FileInputStream对象,构造方法中绑定要读取的数据源
    2. 使用FileInputStream对象中的方法read,读取文件
    3. 释放资源
  3. 优化:while循环【重点】

    1. 读取文件是一个重复的过程,所以可以使用循环优化
    2. 不知道文件多少个字节,使用while循环
    3. while结束条件->读取到-1时候
    4. 格式:(固定)
        int len = 0;    //记录读取到的字符
        while((len = fis.read())!=-1){
            System.out.print((char)len);  //ASCLL码转换为char类型
        }
    
    • 布尔表达式(len = fis.read())!=-1
      1. fis.read():读取一个字节
      2. len = fis.read():把读取到的字节赋值给变量len
      3. (len = fis.read())!=-1:判断变量len是否不等于-1
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\a.txt");
        /*int read = fis.read();
        System.out.println(read);   //97 a

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

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

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

        //使用循环
        int len = 0;
        while((len = fis.read()) != -1){
            System.out.print((char)len);    //abc
        }
        fis.close();
    }

2.9 字节输入流一次读取一个字节的原理

2.10 字节输入流一次读取多个字节

  1. 字节输入流一次读取多个字节的方法:
    • int read(byte[] b):从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
  2. 明确两件事情:
    1. 方法的参数byte[]的作用?
      • 起到缓冲作用,存储每次读取到的多个字节
      • 数组的长度一把定义为1024(1kb)或者1024的整数倍【!】
    2. 方法的返回值int是什么?
      • 每次读取的有效字节个数
  3. String类的构造方法——一次读取多个字节时使用
    • String(byte[] bytes) :把字节数组转换为字符串
    • String(byte[] bytes, int offset, int length):把字节数组的一部分转换为字符串
      • offset:数组的开始索引
      • length:转换的字节个数
        byte[] bytes = new byte[1024]; 
        int len = 0;    
        while((len = fr.read(bytes)) != -1){
            System.out.println(new String(bytes, 0, len));
        }
    
  4. 原理
  5. 优化:while循环【重点】
    • 注:int len = 0; //记录每次读取的有效字节个数
    • 注:这里不能用上面的new String(bytes)
      • 因为这里的长度是1024会有很多空格
      • 要用String(byte[] bytes, int offset, int length)
        • offset–>从哪里开始
        • length–>有效个数(就是len)
    import java.io.FileInputStream;
    import java.io.IOException;

    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\b.txt");

        /*byte[] bytes = new byte[2];
        int len = fis.read(bytes);
        System.out.println(len);    //2
        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
        byte[] bytes = new byte[1024];
        int len = 0;    //记录每次读取的有效字节个数
        while((len = fis.read(bytes)) != -1){
            System.out.println(new String(bytes, 0, len));  //len就是他的有效字节个数
        }

        fis.close();
    }
    
    //结果:
    ABCDE

2.11 练习_文件复制

  1. 原理
  2. 文件复制练习:一读一写
  3. 明确:
    • 数据源: F:\picture\1.jpg
    • 数据的目的地: E:\picture\1.jpg
  4. 文件复制的步骤:
    1. 创建一个字节输入流对象,构造方法中绑定要读取的数据源
    2. 创建一个字节输出流对象,构造方法中绑定要写入的目的地
    3. 使用字节输入流对象中的方法read读取文件
    4. 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
    5. 释放资源
      • 注:先关写入的(如果写入完了,读取肯定完了)
  5. 读写方式:
    1. 读取一个字节写入一个字节的方式(一)
        int len = 0;    //记录每次读取的有效字节个数
        while((len = fis.read()) != -1){
            //使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
            fos.write(len);
        }
    
    1. 使用数组缓冲读取多个字节,写入多个字节(二,常用)
        byte[] bytes = new byte[1024];
        int len = 0;    //每次读取的有效字节个数
        while((len = fis.read(bytes)) != -1){
            //使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
            fos.write(bytes, 0, len);   //从几开始,到多少的有效个数
        }
    
  • 注:只要是文件都可以复制
    public static void main(String[] args) throws IOException {
        //1. 创建一个字节输入流对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("F:\\picture\\1.jpg");
        //创建一个字节输出流对象,构造方法中绑定要写入的目的地
        FileOutputStream fos = new FileOutputStream("E:\\picture\\1.jpg");
        ///使用字节输入流对象中的方法read读取文件
        /*//读取一个字节写入一个字节的方式(一)
        int len = 0;
        while((len = fis.read()) != -1){
            //使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
            fos.write(len);
        }*/

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

        //释放资源(先关写入的)
        fos.close();
        fis.close();
    }

2.12 使用字节流读取中文的问题

  1. 使用字节流读取中文文件
  2. 1个中文
    • GBK:占用两个字节
    • UTF-8:占用3个字节
  3. “你好”出来的是6个数字,一旦转成char就会乱码
        public static void main(String[] args) throws IOException {
            FileInputStream fis = new FileInputStream("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\c.txt");
    
            int len = 0;
            while((len = fis.read()) != -1){
                System.out.println((char)len);
            }
    
            fis.close();
        }
        //结果:
        ä
        ½
         
        å
        ¥
        ½
    
    • 一次读取的就是三分之一的字节
  4. 解决方法:
    使用第三章的字符流–>一次读取一个字符

第三章 字符流

3.1 字符输入流_Reader类&FileReader类介绍

  1. java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类
  2. 共性的成员方法:
    • int read():读取单个字符并返回。
    • int read(char[] cbuf):一次读取多个字符,将字符读入数组。
      • 例:char[] chars = new char[1024];
    • void close():关闭该流并释放与之关联的所有资源。
  3. java.io.FileReader extends InputStreamReader extends Reader(多继承)
  4. FileReader:文件字符输入流
  5. 作用:把硬盘文件中的数据以字符的方式读取到内存中
  6. 构造方法:
    • FileReader(String fileName)
    • FileReader(File file)
    1. 参数:读取文件的数据源
      • String fileName:文件的路径
      • File file:一个文件
    2. FileReader构造方法的作用:
      1. 创建一个FileReader对象
      2. 会把FileReader对象指向要读取的文件

3.2 字符输入流读取字符数据(使用方式一样)

  1. 字符输入流的使用步骤【重点】:
    1. 创建FileReader对象,构造方法中绑定要读取的数据源
    2. 使用FileReader对象中的方法read读取文件
    3. 释放资源
  2. String类的构造方法——一次读取多个字符时使用
    • String(char[] value):把字符数组转换为字符串
    • String(char[] value, int offset, int count):把字符数组的一部分转换为字符串 offset数组的开始索引 count转换的个数
        char[] chars = new char[1024];  //存储读取到的多个字符
        int len = 0;    //记录的是每次读取的有效字符个数
        while((len = fr.read(chars)) != -1){
            System.out.println(new String(chars, 0, len));
        }
    
    public static void main(String[] args) throws IOException {

        FileReader fr = new FileReader("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\c.txt");

        //int ==read==():读取单个字符并返回。
        /*int len = 0;
        while((len = fr.read()) != -1){
            System.out.print((char)len);
        }*/

        //int ==read==(==char[] cbuf==):一次读取多个字符,将字符读入数组。
        char[] chars = new char[1024];  //存储读取到的多个字符
        int len = 0;    //记录的是每次读取的有效字符个数
        while((len = fr.read(chars)) != -1){
            System.out.println(new String(chars, 0, len));
        }

        fr.close();
    }
    
    //结果:
    你好abc123

3.3 字符输出流_Writer类&FileWriter类介绍

  1. java.io.Writer:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类
  2. 共性的成员方法:
    • 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() 关闭此流,但要先刷新它。
  3. java.io.FileWriter extends OutputStreamWriter extends Writer
  4. FileWriter:文件字符输出流
  5. 作用:把内存中字符数据写入到文件中
  6. 构造方法:
    • FileWriter(File file):根据给定的 File 对象构造一个 FileWriter 对象。
    • FileWriter(String fileName):根据给定的文件名构造一个 FileWriter 对象。
    1. 参数:写入数据的目的地
      • String fileName:文件的路径
      • File file:是一个文件
    2. 构造方法的作用:
      1. 会创建一个FileWriter对象
      2. 会根据构造方法中传递的文件/文件的路径,创建文件
      3. 会把FileWriter对象指向创建好的文件

3.4 字符输出流的基本使用_写出单个字符到文件

  1. 字符输出流的使用步骤(重点):
    1. 创建FileWriter对象,构造方法中绑定要写入数据的目的地
    2. 使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
    3. 使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中
    4. 释放资源(会先把内存缓冲区中的数据刷新到文件中【flush可以不用写】)
  2. 字节流和字符流的区别
    • 字节:写入到文件中
    • 字符:写入到内存缓存区中
    public static void main(String[] args) throws IOException {
        //1. 创建FileWriter对象,构造方法中绑定要写入数据的目的地
        FileWriter fw = new FileWriter("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\d.txt");

        //2. 使用FileWriter中的方法==write==,把==数据写入到内存缓冲区中==(字符转换为字节的过程)
        //写入单个字符方式
        fw.write(97);

        //3. 使用FileWriter中的方法==flush==,==把内存缓冲区中的数据,刷新到文件中==
        //fw.flush();

        //4. 释放资源(==会先把内存缓冲区中的数据刷新到文件中【flush可以不用写】==)
        fw.close();
    }

3.5 flush方法和close方法的区别

  1. flush方法和close方法的区别
    • flush :刷新缓冲区,流对象可以继续使用。
    • close: 先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
    public static void main(String[] args) throws IOException {
        //1. 创建FileWriter对象,构造方法中绑定要写入数据的目的地
        FileWriter fw = new FileWriter("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\e.txt");

        //2. 使用FileWriter中的方法==write==,把==数据写入到内存缓冲区中==(字符转换为字节的过程)
        //写入单个字符方式
        fw.write(97);

        //3. 使用FileWriter中的方法==flush==,==把内存缓冲区中的数据,刷新到文件中==
        fw.flush();
        //刷新之后,流可以继续使用
        fw.write(98);

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

3.6 字符输出流写数据的其他方法

  1. 字符输出流写数据的其他方法
    • 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 main(String[] args) throws IOException {
        //1. 创建FileWriter对象,构造方法中绑定要写入数据的目的地
        FileWriter fw = new FileWriter("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\f.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写的字符个数。
        //写入字符数组cs中间三个
        fw.write(cs, 1, 3); //bcd

        //void write(String str)==写入字符串==。
        fw.write("魔鬼筋肉人");  //魔鬼筋肉人

        //void write(String str, int off, int len)
        //写后三个
        fw.write("Java程序员", 4, 3);  //程序人

        fw.close();
    }

3.7 字符输出流的续写和换行

  1. 续写,追加写:使用两个参数的构造方法
    • FileWriter(String fileName, boolean append)
    • FileWriter(File file, boolean append)
    1. 参数:
      • String fileName,File file:写入数据的目的地
      • boolean append:续写开关
        • true:不会创建新的文件覆盖源文件,可以续写
        • false:创建新的文件覆盖源文件
  2. 换行:换行符号
    • windows:\r\n
    • linux:/n
    • mac:/r
  • 字节流和字符流换行的区别
    • 字节流:因为写入的是字节数组,所以需要把"\r\n"这个字符串转为字节数组
          for(int i = 0; i < 2; i++){
              fos.write("你好".getBytes());
              fos.write("\r\n".getBytes());
          }
      
    • 字符流:写入的可以是字符或者字符串,所以不需要转换
          for(int i = 0; i < 2; i++){
              fw.write("你好" + "\r\n");
          }
      
    public static void main(String[] args) throws IOException {
        //1. 创建FileWriter对象,构造方法中绑定要写入数据的目的地
        FileWriter fw = new FileWriter("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\g.txt", true);

        for(int i = 0; i < 2; i++){
            fw.write("你好" + "\r\n");
        }

        fw.close();
    }
    
    //结果:
    你好
    你好

第四章 IO异常的处理

4.1 使用try_catch_finally处理流中的异常

  1. jdk1.7之前使用try catch finally 处理流中的异常
    1. 格式:
        try{
            可能会产出异常的代码
        }catch(异常类变量 变量名){
            异常的处理逻辑
        }finally{
            一定会指定的代码
            资源释放
        }
    
  • 注:变量在定义的时候,可以没有值,但是使用的时候必须有值
  • 注:fw = new FileWriter(“Dark-horse-teaching\src\cn\javaadvance\day09\g.txt”, true);
    • 执行失败,fw没有值,fw.close();就会报错
    • 给FileWriter fw;一个null
    • FileWriter fw = null;
  • 注:finally中的catch也有异常的,需要单独的try…catch
  • 注:finally中:创建对象失败了,fw的默认值就是null,null是不能调用方法的,会抛出NullPointerException,需要增加一个判断,不是null在把资源释放
    public static void main(String[] args) {
            //增大作用域
            FileWriter fw = null;
            try{
                fw = new FileWriter("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\g.txt", true);

                for(int i = 0; i < 2; i++){
                    fw.write("你好" + "\r\n");
                }
            }catch (IOException e){
                System.out.println(e);
            }finally {
                //==创建对象失败==了,==fw的默认值就是null==,==null是不能调用方法的,会抛出NullPointerException==,需要==增加一个判断,不是null在把资源释放==
                if(fw != null){
                    try {
                        fw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    }

4.2 JDK7和JDK9流中异常的处理

  1. JDK7的新特性
    1. 在try的后边可以增加一个(),在括号中可以定义流对象
    2. 那么这个流对象的作用域就在try中有效
    3. try中的代码执行完毕,会自动把流对象释放,不用写finally
    4. 格式:
        try(定义流对象;定义流对象....){
            可能会产出异常的代码
        }catch(异常类变量 变量名){
            异常的处理逻辑
        }
    
    public static void main(String[] args) {
        try(//1. 创建一个字节输入流对象,构造方法中绑定要读取的数据源
            FileInputStream fis = new FileInputStream("F:\\picture\\1.jpg");
            //创建一个字节输出流对象,构造方法中绑定要写入的目的地
            FileOutputStream fos = new FileOutputStream("E:\\picture\\1.jpg");){
            ///使用字节输入流对象中的方法read读取文件
            //读取一个字节写入一个字节的方式(一)
            int len = 0;
            while((len = fis.read()) != -1){
                //使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
                fos.write(len);
            }
            
        }catch (IOException e){
            System.out.println(e);
        }
    }
  1. JDK9的新特性:
    1. try的前边可以定义流对象
    2. 在try后边的()中可以直接引入流对象的名称(变量名)
    3. 在try代码执行完毕之后,流对象也可以释放掉,不用写finally
    4. 格式:
        A a = new A();
        B b = new B();
        try(a,b){
            可能会产出异常的代码
        }catch(异常类变量 变量名){
            异常的处理逻辑
        }
    
    public static void main(String[] args) throws IOException {
        //1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("c:\\1.jpg");
        //2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
        FileOutputStream fos = new FileOutputStream("d:\\1.jpg");

        try(fis;fos){
            //一次读取一个字节写入一个字节的方式
            //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

    }

第五章 属性集

5.1 使用Properties集合存储数据,遍历取出Properties集合中的数据

  1. java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>
    • Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。
    • Properties集合是一个唯一和IO流相结合的集合
      • 可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
      • 可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
    • 属性列表中每个键及其对应值都是一个字符串
      • Properties集合是一个双列集合,key和value默认都是字符串
      • 所以不用写泛型
  2. 使用Properties集合存储数据,遍历取出Properties集合中的数据
    • Properties集合是一个双列集合,key和value默认都是字符串
    • Properties集合有一些操作字符串的特有方法
      • Object setProperty(String key, String value):调用 Hashtable 的方法 put
      • String getProperty(String key):通过key找到value值,此方法相当于Map集合中的get(key)方法
      • Set stringPropertyNames():返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
    public class Demo01Properties {
        public static void main(String[] args) {
            show1();
        }
    
        private static void show1() {
            //创建Properties对象
            Properties prop = new Properties();
            //使用setProperty往集合中添加数据
            prop.setProperty("赵丽颖", "168");
            prop.setProperty("古力娜扎", "170");
            prop.setProperty("迪丽热巴", "165");
    
            //使用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);
            }
        }
    }
    
    //结果:
    赵丽颖=168
    古力娜扎=170
    迪丽热巴=165

5.2 Properties集合中的方法store

  1. 可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
    • void store(OutputStream out, String comments)
    • void store(Writer writer, String comments)
    1. 参数:
      • OutputStream out:字节输出流,不能写入中文【!】
      • Writer writer:字符输出流,可以写中文
      • String comments:注释,用来解释说明保存的文件是做什么用的
        • 不能使用中文,会产生乱码,默认是Unicode编码
        • 一般使用""空字符串
  2. 使用步骤:
    1. 创建Properties集合对象,添加数据
    2. 创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
    3. 使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
    4. 释放资源
    public class Demo01Properties {
        public static void main(String[] args) throws IOException {
            //show1();
            shoow2();
        }
    
        //Properties集合中的方法store,集合中的临时数据,持久化写入到硬盘中存储
        private static void shoow2() throws IOException {
            //1.创建Properties集合对象,添加数据
            Properties prop = new Properties();
            prop.setProperty("赵丽颖", "168");
            prop.setProperty("古力娜扎", "170");
            prop.setProperty("迪丽热巴", "165");
    
            /*
            //2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
            //FileOutputStream fos = new FileOutputStream("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\g.txt");
            FileWriter fw = new FileWriter("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\prop.txt");
    
            //3. 使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
            prop.store(fw, "save data");
    
            //4. 释放资源
            fw.close();
    
             */
    
            //匿名对象使用完自动关了,不需要释放资源
            //字节写入中文会出来乱码
            prop.store(new FileOutputStream("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\prop2.txt"), "");
    
        }
    }
    
    //字符写入中文结果:
    #save data
    #Tue Feb 25 11:31:00 CST 2020
    赵丽颖=168
    古力娜扎=170
    迪丽热巴=165
    //字节写入中文结果:
    #
    #Tue Feb 25 11:33:22 CST 2020
    \u8D75\u4E3D\u9896=168
    \u53E4\u529B\u5A1C\u624E=170
    \u8FEA\u4E3D\u70ED\u5DF4=165

5.3 Properties集合中的方法load【重点】

  1. 可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
    • void load(InputStream inStream)
    • void load(Reader reader)
    1. 参数:
      • InputStream inStream:字节输入流,不能读取含有中文的键值对
      • Reader reader:字符输入流,能读取含有中文的键值对
  2. 使用步骤:
    1. 创建Properties集合对象
    2. 使用Properties集合对象中的方法load读取保存键值对的文件
    3. 遍历Properties集合
  3. 注意:
    1. 存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
    2. 存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
    3. 存储键值对的文件中,键与值默认都是字符串,不用再加引号
    4. 因为字节流读取到中文会有乱码,所以我们一般都使用字符流
    public class Demo01Properties {
        public static void main(String[] args) throws IOException {
            //show1();
            //shoow2();
            show3();
        }
    
        //可以使用Properties集合中的方法load,==把硬盘中保存的文件(键值对),读取到集合中使用==
        private static void show3() throws IOException {
            //1. 创建Properties集合对象
            Properties prop = new Properties();
            //2. 使用Properties集合对象中的方法load读取保存键值对的文件
            prop.load(new FileReader("Dark-horse-teaching\\src\\cn\\javaadvance\\day09\\prop.txt"));
            //3. 遍历Properties集合
            Set<String> set = prop.stringPropertyNames();
            //增强for
            /*for (String key : set) {
                String value = prop.getProperty(key);
                System.out.println(key + "=" + value);
            }*/
            //Iterator迭代器
            Iterator<String> it = set.iterator();
            while(it.hasNext()){
                String key = it.next();
                String value = prop.getProperty(key);
                System.out.println(key + "=" + value);
            }
        }
    }
    
    //结果:
    赵丽颖=168
    古力娜扎=170
    迪丽热巴=165
发布了42 篇原创文章 · 获赞 6 · 访问量 1130

猜你喜欢

转载自blog.csdn.net/qq_40572023/article/details/104764492