3.1_14 JavaSE入门 P13 【其他】异常,File,IO,字节(符)流,字节(符)缓冲流,转换流

相关链接

  • Excel目录

目录

  • P13 【其他】异常,File,IO,字节(符)流,字节(符)缓冲流,转换流
    • 1 异常
      • 1.1 异常的概述
      • 1.2 JVM默认处理异常方式
      • 1.3 编译时异常&运行时异常 区别
      • 1.4 异常处理1:try catch
      • 1.5 异常处理2:throws
    • 2 File类
      • 2.1 File类的概述
      • 2.2 File类的方法
        • 2.2.1 创建
        • 2.2.2 删除
        • 2.2.3 判断&获取
    • 3 IO流
      • 3.1 字节流
        • 3.1.1 FOS与FIS
        • 3.1.2 FOS写数据的三种方式
        • 3.1.3 FOS如何实现换行和追加写数据
        • 3.1.4 FOS写数据加入异常处理
        • 3.1.5 FIS读数据方式1一次读取一个字节
        • 3.1.6 FIS读数据方式2一次读取一个字节数组
        • 3.1.7 字节流练习之复制文本文件
        • 3.2.8 字节流练习之复制图片
      • 3.2 字节缓冲区流
        • 3.2.1 概述
        • 3.2.2 四种方式复制图片效率测试
      • 3.3 转换流
        • 3.3.1 什么是编码表
        • 3.3.2 String类的编解码
        • 3.3.3 字符流Stream的编解码(写入文件)
      • 3.4 字符流
        • 3.4.1 复制Java文件
        • 3.4.3 OutputStreamWriter写数据的6种方式
        • 3.4.3 InputStreamReader读数据的2种方式
      • 3.5 字符缓冲区流
        • 3.5.1 概述
        • 3.5.2 复制文本文件
        • 3.5.3 复制Java文件
        • 3.5.4 字符缓冲区流的特殊功能
    • 4 NIO(new IO)
    • 5 IO流练习
      • 5.1 练习1 键盘写入文件
      • 5.2 练习2 学生信息写入文件
      • 5.3 练习3 读取文件修改指定内容
      • 5.4 练习4 读取文件反转行
      • 5.5 练习5 字符流五种方式读写
      • 5.6 练习6 ArrayList到TXT
      • 5.7 练习7 TXT到ArrayList
      • 5.8 练习8 Array\


P13 【其他】异常,File,IO,字节(符)流,字节(符)缓冲流,转换流


1 异常


1.1 异常的概述


  • 异常的概念
    • 异常(Exception类):就是程序出现了不正常的情况。下面举例:
    • 【ArithmeticException】:当出现异常的运算条件(例如一个整数“除以零”)时,抛出此异常(此类的一个实例)。

  • 常见的异常有
    • IndexOutOfBoundsException : 数组越界异常,访问的元素超出了数组范围
    • NullPointerException : 空指针异常,一般在使用对象的方法时会出现,对象为null,所以不能调用该对象的方法。
    • StringIndexOutOfBoundsException : 字符串索引越界异常,String类也可以视为数组,可以理解为字符类型数组越界异常。
      • 在使用String类的如 charAt(int index); subString(int beginIndex, int endIndex); 方法时,index参数超过String数组本身范围,则会报出这个错误。

  • 异常的体系的介绍
    • Throwable 类是 Java 语言中所有错误或异常的超类。
    • Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。
      • 也就是说针对程序发生了Error的情况,Java程序本身是无能为力的,比如说:硬件层面的问题,内存不足等。
      • 所以,针对Error的问题我们不处理。
    • Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。
      • 也就是说针对程序发生了Exception的情况,是我们需要处理的问题。

  • Exception的分类
    • 运行期的异常(RunTimeException):在编译期是不处理的,在程序运行时候出现了问题,需要我们回来修改代码。
    • 编译期的异常(非RunTimeException):在编译期就必须处理,否则程序不能通过编译,就更不能正常的执行了。

  • 异常的两种处理方式
    • 方式一try catch (快捷键 ctrl + alt + t)
      try {
          //尝试对此部分代码捕获异常
      } catch (Exception e) {
          //捕获异常后的处理逻辑
          //e.printStackTrace(); //默认处理方式打印异常信息
      } finally {
          //无论是否捕获异常,都会执行
      }  
      
    • 方式二throws Exception
      • 如果你采用了throws这种方案,将来谁调用,还得进行处理。
      • 运行时异常可以不用处理,出现问题后我们需要回来修改代码。
       //以IOException为例,只有使用BufferedReader就会出现找不到文件IO异常,需要进行处理
       public static void main(String[] args) throws IOException {
       	BufferedReader br = new BufferedReader(new FileReader("name.txt"));
       }
      

1.2 JVM默认处理异常方式


  • 处理方案
    • A:把异常的名称,异常的原因,异常出现的位置等信息在控制台输出
    • B:让程序停止执行

案例代码一JVM默认处理异常方式

package com.groupies.base.day13;

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction JVM默认处理异常方式
 *
 * 处理方案:
 * 		A:把异常的名称,异常的原因,异常出现的位置等信息在控制台输出
 * 		B:让程序停止执行
 */
public class Demo1Exception {
    public static void main(String[] args) {
        /*
            程序开始执行
            Exception in thread "main" java.lang.ArithmeticException: / by zero
                at com.groupies.base.day13.Demo1Exception.method(Demo1Exception.java:28)
                at com.groupies.base.day13.Demo1Exception.main(Demo1Exception.java:21)
         */
        System.out.println("程序开始执行");
        method();//【报错定位】第21行
        System.out.println("程序结束执行");
    }

    public static void method(){
        int a = 10;
        int b = 0;
        System.out.println(a / b);//【报错定位】第28行
    }
}

1.3 编译时异常&运行时异常 区别


  • Java中的异常被分为两大类:编译时异常运行时异常
    • 所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常都是编译时异常;
    • 编译时异常:Java程序必须显示处理,否则程序就会发生错误的一个提示,无法通过编译;
    • 运行时异常:Java程序无需显示处理,也可以和编译时异常一样处理。

1.4 异常处理1:try catch


  • 异常的两种处理方式

  • 方式一try catch (快捷键 ctrl + alt + t)
    • 执行流程
      • 程序从try开始执行,执行到哪里出现了问题,就会跳转到catch里面执行;
      • 执行完毕后,程序还能继续往下执行;
      • 无论是否捕获异常 都一定会执行finally部分的代码。
    try {
        //尝试对此部分代码捕获异常
    } catch (Exception e) {
        //捕获异常后的处理逻辑
        //e.printStackTrace(); //默认处理方式打印异常信息
    } finally {
        //无论是否捕获异常,都会执行
    }
    

  • 方式二throws Exception
    • 如果你采用了throws这种方案,将来谁调用,还得进行处理。
    • 运行时异常可以不用处理,出现问题后我们需要回来修改代码。
    //以IOException为例,只有使用BufferedReader就会出现找不到文件IO异常,需要进行处理
    public static void main(String[] args) throws IOException {
     BufferedReader br = new BufferedReader(new FileReader("name.txt"));
    }
    

  • try catch 获异常后, 如何处理?
    • public void printStackTrace():把异常的错误信息输出在了控制台。
    • 在实际开发中,我们遇见了异常,会给出一个页面进行提示,而我们目前做不了,
    • 所以,就用异常对象调用printStackTrace()就可以了。

  • try…catch处理方式&JVM的默认处理方式有什么不同?
    • 首先要明确try…cathc处理方式的特点, 产生了问题, 是自己将问题处理掉, 不影响后续代码的运行.
    • JVM默认处理方式是将程序终止, 并将异常信息打印在控制台.
    • 但这种方式很显然用户体验度不佳, 所以这时候就可以考虑使用try…cathc将问题捕获并处理掉.
    • 这样就不会影响程序的继续执行了

案例代码二try…catch处理异常

package com.groupies.base.day13;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction try..catch处理异常
 *
 * 为什么要有throws处理方式?
 * 	 我们通过try...catch可以对异常进行处理了,但是并不是所有的时候我们都有权限进行异常的处理。
 *   		也就是说,有些时候我们处理不了,但是,这个时候异常时存在的,不处理也不行,怎么办?
 *   		这个时候,Java就提供了throws的处理方案。
 *
 * try..catch的格式和执行流程为
 *      格式:
 *          try {
 *   		    可能出现异常的代码;
 *          }catch(异常类名  变量名) {
 *   	        异常的处理代码;
 *          }
 *
 *      执行流程:
 *          程序从try开始执行,执行到哪里出现了问题,就会跳转到catch里面执行。
 *   	    执行完毕后,程序还能继续往下执行。
 *
 * 捕获异常后,  如何处理?
 *      public void printStackTrace():把异常的错误信息输出在了控制台。
 *   	在实际开发中,我们遇见了异常,会给出一个页面进行提示,而我们目前做不了,
 *   	所以,就用异常对象调用printStackTrace()就可以了。
 *
 *  try..catch处理方式&JVM的默认处理方式有什么不同
 *      首先要明确try..cathc处理方式的特点, 产生了问题, 是自己将问题处理掉, 不影响后续代码的运行.
 *      JVM默认处理方式是将程序终止, 并将异常信息打印在控制台.
 * 	    但这种方式很显然用户体验度不佳, 所以这时候就可以考虑使用try..cathc将问题捕获并处理掉.
 * 	    这样就不会影响程序的继续执行了
 */
public class Demo2TryCatch {
    public static void main(String[] args) {
        System.out.println("-----程序开始执行-----");
        System.out.println("method: 编译时异常");
        method();//日期格式不合法,请重新输入
        System.out.println("method2: 运行时异常");
        method2();//除数不能为0
        System.out.println("-----程序结束执行-----");
    }

    //编译时异常ParseException
    public static void method() {
        //String s = "2088-08-08";
        String s = "abcd";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date d = null;
        try {
            //如果不抛出异常,也不使用try catch捕获异常,则会提示如下信息:不能通过编译
            //java: 未报告的异常错误java.text.ParseException; 必须对其进行捕获或声明以便抛出
            d = sdf.parse(s);
        } catch (ParseException e) {
            //e.printStackTrace();//不打印异常信息
            System.out.println("日期格式不合法,请重新输入");
        }
        System.out.println(d);
    }

    //运行时异常
    public static void method2() {
        try {
            int a = 10;
            int b = 0;
            System.out.println(a / b);
        } catch (ArithmeticException e) {
            //e.printStackTrace();//不打印异常信息
            System.out.println("除数不能为0");
        }
    }
}

1.5 异常处理2:throws


  • 为什么要有throws处理方式?
    • 我们通过try…catch可以对异常进行处理了,但是并不是所有的时候我们都有权限进行异常的处理。
    • 也就是说,有些时候我们处理不了,但是,这个时候异常时存在的,不处理也不行,怎么办?
    • 这个时候,Java就提供了throws的处理方案。

  • throws使用的格式
    • throws 异常类名
    • 注意:这个格式必须跟在方法的括号的后面
       //实例
       public static void main(String[] args) throws Exception {
       	BufferedReader br = new BufferedReader(new FileReader("name.txt"));
       }
      

  • throws使用的注意事项?
    • 编译时异常时必须要进行处理的,两种处理方案:try…catch…或者throws
    • 如果你采用了throws这种方案,将来谁调用,还得进行处理。
    • 运行时异常可以不用处理,出现问题后我们需要回来修改代码。

案例代码三throws处理异常

package com.groupies.base.day13;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction throws处理异常
 *
 * 为什么要有throws处理方式?
 * 	 我们通过try...catch可以对异常进行处理了,但是并不是所有的时候我们都有权限进行异常的处理。
 *   		也就是说,有些时候我们处理不了,但是,这个时候异常时存在的,不处理也不行,怎么办?
 *   		这个时候,Java就提供了throws的处理方案。
 *
 * throws使用的格式&注意事项?
 *      格式:
 *   		throws 异常类名
 *   		注意:这个格式必须跟在方法的括号的后面
 *
 *   	注意:
 *   		编译时异常时必须要进行处理的,两种处理方案:try...catch...或者throws
 *   		如果你采用了throws这种方案,将来谁调用,还得进行处理。
 *
 *   		运行时异常可以不用处理,出现问题后我们需要回来修改代码。
 */
public class Demo3Throws {
    public static void main(String[] args)   {
        System.out.println("程序开始执行");
        try {
            /*
            java.text.ParseException: Unparseable date: "abc"
                at java.text.DateFormat.parse(DateFormat.java:366)
                at com.groupies.base.day13.Demo3Throws.method(Demo3Throws.java:55)
                at com.groupies.base.day13.Demo3Throws.main(Demo3Throws.java:38)
             */
            method();//【报错定位】第38行
        } catch (ParseException e) {
            e.printStackTrace();
        }
        /*
        Exception in thread "main" java.lang.ArithmeticException: / by zero
            at com.groupies.base.day13.Demo3Throws.method2(Demo3Throws.java:63)
            at com.groupies.base.day13.Demo3Throws.main(Demo3Throws.java:47)
         */
        method2();
        System.out.println("程序结束执行");
    }

    //编译时异常 注意导包 import java.text.ParseException;
    public static void method() throws ParseException {
        String s = "abc";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date d = sdf.parse(s);//【报错位置】第55行
        System.out.println(d);
    }

    //运行时异常
    public static void method2() throws ArithmeticException {
        int a = 10;
        int b = 0;
        System.out.println(a / b);//【报错定位】第63行
    }
}

2 File类


2.1 File类的概述


  • File :文件和目录路径名的抽象表示形式
    • 也就是说文件和目录(文件夹)是可以通过File封装成对象的

  • File类的构造方法
    //a. 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
    File(String pathname)
    //b. 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
    File(String parent, String child)
    //c. 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实
    File(File parent, String child)
    

案例代码四File类的构造方法

package com.groupies.base.day13;

import java.io.File;

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction File类的构造方法
 *
 * file构造方法:
 *   	a. File(String pathname):通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
 *   	b. File(String parent, String child):根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
 *   	c. File(File parent, String child):根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实
 *
 */
public class Demo4File {
    public static void main(String[] args) {
        //以下的f1,f2,f3做的是同样的事情,就是把d:\\aa\\b.txt转换为了一个File对象

        //a. File(String pathname)
        File f1 = new File("d:\\aa\\b.txt");

        //b. File(String parent, String child)
        File f2 = new File("d:\\aa", "b.txt");

        //c. File(File parent, String child)
        File f3_path = new File("d:\\aa");
        File f3 = new File(f3_path, "b.txt");
    }
}

2.2 File类的方法


2.2.1 创建

  • 方法摘要
    //a.创建文件 如果文件不存在,创建文件并返回true 如果文件存在,创建文件失败并返回false
    public boolean createNewFile():
    	
    //b.创建目录 如果目录不存在,创建目录并返回true 如果目录存在,创建目录失败并返回false
    public boolean mkdir()
    
    //c.创建多级目录
    public boolean mkdirs()
    

案例代码五File类方法–创建

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction File类方法--创建
 *
 * 创建功能
 *  	a. File.createNewFile():创建文件
 *  		如果文件不存在,创建文件并返回true
 *  		如果文件存在,创建文件失败并返回false
 *  	b. File.mkdir():创建目录
 * 		    如果目录不存在,创建目录并返回true
 *  		如果目录存在,创建目录失败并返回false
 *      c. File.mkdirs():创建多级目录
 *
 * File.separator
 *      其实File.separator 的作用相当于 '\'
 *      在 windows 中文件文件分隔符 用 '\' 或者'/' 都可以
 *      但是在 Linux 中,是不识别 '\'的,而File.separator 是系统默认的文件分隔符号,在 UNIX 系统上,此字段的值为'/'
 *      在Microsoft Windows 系统上,它为 '\'屏蔽了这些系统的区别。
 *      所以用 File.separator 保证了在任何系统下不会出错。
 *
 *   需求:
 *      1:【createNewFile】 在d盘目录下创建一个文件a.txt
 *      2:【mkdir】 在d盘目录下创建一个目录bb
 *      3:【mkdirs】 在d盘目录下创建一个多级目录cc\\dd
 *      4:【mkdir + createNewFile】 在d盘目录下创建一个文件ee\\f.txt
 */
public class Demo5FileMethodCreate {
    public static void main(String[] args) {
        //需求1:我要在d盘目录下创建一个文件a.txt
        File f1 = new File("D:\\a.txt");//1.createNewFile:true
        try {
            System.out.println("1.createNewFile:" + f1.createNewFile());
        } catch (IOException e) {
            System.out.println("IO异常,创建失败");
        }

        //需求2:我要在d盘目录下创建一个目录bb
        File f2 = new File("D:" + File.separator + "bb");
        System.out.println("2.mkdirs:" + f2.mkdirs());//2.mkdirs:true

        //需求3:我要在d盘目录下创建一个多级目录cc\\dd
        File f3 = new File("D:\\cc" + File.separator + "dd");
        System.out.println("3.mkdirs:" + f3.mkdirs());//3.mkdirs:true

        //需求4:我要在d盘目录下创建一个文件ee\\f.txt
        File f4_path = new File("D:\\ee");
        File f4_file = new File(f4_path, "f.txt");
        System.out.println("4.mkdir:" + f4_path.mkdirs());//5.mkdir:true
        try {
            System.out.println("4.createNewFile:" + f4_file.createNewFile());//5.createNewFile:true
        } catch (IOException e) {
            System.out.println("IO异常,创建失败");
        }
    }
}

2.2.2 删除

  • 相对路径&绝对路径
    • 绝对路径:是以盘符开始的路径。d:\aa\b.txt
    • 相对路径:不以盘符开始。相对于当前的项目而言,在项目的目录下。如何显示出来呢?刷新项目就可以了。

  • 方法摘要
    public boolean delete():删除文件和目录
    

  • 注意事项
    • 如果一个目录中有内容(目录,文件),就不能直接删除。
    • 应该先删除目录中的内容,最后才能删除目录。

案例代码六File类方法–删除

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction File类方法--删除
 *
 * 相对路径&绝对路径
 *   	绝对路径:是以盘符开始的路径。d:\\aa\\b.txt
 *   	相对路径:不以盘符开始。相对于当前的项目而言,在项目的目录下(与src同级目录)。如何显示出来呢?刷新项目就可以了。
 *
 * 方法摘要&注意事项
 *      删除功能
 *          public boolean delete():删除文件和目录
 *
 *      注意:
 *   		如果一个目录中有内容(目录,文件),就不能直接删除。
 *   		应该先删除目录中的内容,最后才能删除目录。
 *
 * 需求:
 *      1. createNewFile:相对路径创建一个文件a.txt
 *      2. mkdir+createNewFile:相对路径创建一个文件cc\\d.txt
 *      3. getAbsolutePath:获取项目根目录路径
 *      4. delete:相对路径删除a.txt这个文件
 *      5. delete: 相对路径删除cc这个目录(先删除d.txt这个文件,再删除cc这个目录)
 */
public class Demo6FileMethodDelete {
    public static void main(String[] args) throws InterruptedException, IOException {
        //需求1. createNewFile:相对路径创建一个文件a.txt.
        File f1 = new File("a.txt");
        System.out.println("1.创建一个文件a.txt: " + f1.createNewFile());

        //需求2. mkdir+createNewFile:相对路径创建一个文件cc\\d.txt
        File f2_path = new File("cc");
        File f2_file = new File("cc" + File.separator + "a.txt");
        System.out.println("3.创建一个目录cc: " + f2_path.mkdirs());
        System.out.println("3.创建一个文件cc\\d.txt: " + f2_file.createNewFile());

        //等待10秒
        File projectPath = new File("");//参数为空,表示当前项目根目录
        System.out.println("全部创建完毕,请进入 " + projectPath.getAbsolutePath() + " 目录查看文件,15秒后开始删除");
        Thread.sleep(15000);//线程等待15秒

        //需求4.delete:相对路径删除a.txt这个文件
        File f4 = new File("a.txt");
        System.out.println("删除a.txt: " + f4.delete());

        //需求5. delete: 相对路径删除cc这个目录(先删除d.txt这个文件,再删除cc这个目录)
        File f5_file = new File("cc" + File.separator + "a.txt");
        File f5_path = new File("cc");
        System.out.println("删除cc\\a.txt文件: " + f5_file.delete());
        System.out.println("删除cc目录: " + f5_path.delete());
    }
}
  • 遍历File目录,删除所有目录下文件
 /**
 * @introduction 遍历File目录,删除所有文件
 * @param f
 */
public static void deleteFile(File f) {//传一个File对象f进去 因为要调用其方法
    if (f != null) {//判断f数据是否为空 因为可能有人会传null值进来
        if (f.exists()) {//判断该抽象路径的目录和文件是否存在
            if (f.isDirectory()) {//判断是否是目录
                File[] listFiles = f.listFiles();//调用listFiles()方法返回一个File对象组成的数组集合
                if (listFiles == null) {//如果该数组为Null说明没有文件和目录对象 就是一个空的文件夹
                    f.delete();//直接删除
                } else {//不为空的文件夹
                    for (File file : listFiles) {//遍历该集合
                        deleteFile(file);//遍历到的每个File对象传入demo()方法
                    }
                    f.delete();//最后将这个不为空的文件夹删除
                }
            } else {//不是目录可能是是文件或者不存在
                f.delete();//直接删除
            }
        } else {//为Null
            return;//结束方法调用
        }
    }
}

2.2.3 判断&获取

  • 方法摘要
    /******a.判断功能******/
    //a1.判断是否是目录
    public boolean isDirectory()
        
    //a2.判断是否是文件
    public boolean isFile()
        
    //a3.判断是否存在
    public boolean exists()
        
    /******b.获取功能******/
    //b1.获取绝对路径
    public String getAbsolutePath()
        
    //b2.获取相对路径
    public String getPath()
        
    //b3.获取名称
    public String getName()
    

案例代码七File类方法–判断、获取

package com.groupies.base.day13;

import java.io.File;

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction File类方法--判断、获取
 *
 * 判断功能
 *        a. File.isDirectory():判断是否是目录
 *   	  b. File.isFile():判断是否是文件
 *   	  c. File.exists():判断是否存在
 * 获取功能
 *   	  d. File.getAbsolutePath():获取绝对路径
 *   	  e. File.getPath():获取相对路径
 *   	  f. File.getName():获取名称
 */
public class Demo7FileMethodJudgeGet {
    public static void main(String[] args) {
        //创建File对象
        File f = new File("aaa" + File.separator + "bbb.txt");

        //判断功能
        System.out.println("-----a. File.isDirectory():判断是否是目录-----");
        System.out.println(f.isDirectory());//false

        System.out.println("-----b. File.isFile():判断是否是文件-----");
        System.out.println(f.isFile());//false

        System.out.println("-----c. File.exists():判断是否存在-----");
        System.out.println(f.exists());//false

        System.out.println("-----d. File.getAbsolutePath():获取绝对路径-----");
        System.out.println(f.getAbsolutePath());//F:\Data_bak\java\base\aaa\bbb.txt

        System.out.println("-----e. File.getPath():获取相对路径-----");
        System.out.println(f.getPath());//aaa\bbb.txt

        System.out.println("-----f. File.getName():获取名称-----");
        System.out.println(f.getName());//bbb.txt
    }
}

3 IO流


  • 什么是IO流,其作用为?
    • I ------ Input --> 输入 --> 读取
    • O — Output --> 输出 --> 写出

  • 常见应用
    • 文件复制
    • 文件上传
    • 文件下载

IO流的分类汇总

  • 按类型分类
    • a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
      • b. 字节缓冲区流 (字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码)
    • c. 转换流 (字符流) = 字节流 + 编码表
    • d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
      • e. 字符缓冲区流

  • a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
    • InputStream 字节流输入超类
      • FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
        • b. 字节缓冲区流BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
    • OutPutStream 字节流输出超类
      • FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
        • b 字节缓冲区流BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码
  • c. 转换流 (字符流) = 字节流 + 编码表
  • d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
    • Reader 字符流输入超类
    • InputStreamReader 用 默认/指定 编码读数据
      • FileReader ↓作为BufferedReader构造器的参数使用↓
      • e. 字符缓冲区流BufferedReader 最常用
    • Writer 字符流输出超类
      • PrintWriter
      • OutputStreamWriter 用 默认/指定 编码写数据
        • FileWriter ↓作为BufferedWriter构造器的参数使用↓
      • e. 字符缓冲区流BufferedWriter 最常用

  • IO流的分类 throws FileNotFoundException
    • 按类型分类
      • a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
        • a1  InputStream 字节流输入超类
          • a1.1  FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
            //指定输入流
            //FileInputStream fis = new FileInputStream(new File("fis.txt"));//效果同下行代码
            FileInputStream fis = new FileInputStream("fis.txt");
            
            //a.一次读取一个字符
              int by;
            //如果fis.read不等于-1说明还有数据,则继续读文件
              while ((by = fis.read()) != -1) {
              	System.out.print((char) by);//打印结果
              }
            
              //b.一次读取一个字符数组
              byte[] bys = new byte[1024];//每次读取最大bys长度个字节存入数组,长度建议1024或1024的整数倍
              int len;//代表有效个数
              //将数据读取到数组中, 并用len记录读取到的有效字节个数
              //fis.read(bys)=>读取一次bys长度内容写入bys(每次覆盖之前内容),如果剩余文件内容不足以写满bys,(长度1024,剩余1000字节)则bys中最后字节(24字节)保持上一次写入的内容 => 所以每次要截取new String(bys,0,len),避免读到上一次剩余的内容
              while ((len = fis.read(bys)) != -1) {
              	System.out.print(new String(bys, 0, len));//打印结果
              }
            
              //释放资源
              fis.close();
            
            • b1. 字节缓冲区流BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
                //字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流
                
                //Q:为什么字节缓冲流的构造方法需要传入一个In/OutputStream
                //A:字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作。
                    
                //指定输入流
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream("name.txt"));
                
                //a.一次读取一个字符(不能读取中文,中文一般2-4字节,一个一个字节读会乱码)
                int by;
                while ((by = bis.read()) != -1) {
                    System.out.print((char) by);
                }
                
                //b.一次读取一个字符数组
                byte[] bys = new byte[1024];
                int len;
                while ((len = bis.read(bys)) != -1) {
                    System.out.print(new String(bys, 0, len));
                }
                
                //释放资源
                bis.close();
              
        • a2  OutPutStream 字节流输出超类
          • a2.1  FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
            //指定输出流
            //FileOutputStream fos = new FileOutputStream(new File("fos.txt"));//效果同下行代码
            //FileOutputStream fos = new FileOutputStream("fos.txt" , false);//false表示不追加文件->每次写入覆盖之前的内容
            FileOutputStream fos = new FileOutputStream("fos.txt");
            
            FileInputStream fis = new FileInputStream("fis.txt");
            
            //a.一次写入一个字符(不能读取中文,中文一般2-4字节,一个一个字节读会乱码)
            int by;
            while ((by = fis.read()) != -1) {
            	System.out.print((char) by);//打印结果
            }
            
            //b.一次写入一个字符数组
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
            	fos.write(bytes, 0, len);
            }
            
            //释放资源
            fos.close();
            fis.close();
            
            • b2. 字节缓冲区流BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码
              //字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流
              
              //Q:为什么字节缓冲流的构造方法需要传入一个In/OutputStream
              //A:字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作。
              
              //指定输入流
              BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
              BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
              
              //a.一次读取一个字符
              int by;
              while ((by = bis.read()) != -1) {
                  bos.write(by);//写入字符串
                  bos.flush();//刷新该流的缓冲,写入文件
              }
              
              //b.一次读取一个字符数组
              byte[] bytes = new byte[1024];
              int len;
              while ((len = bis.read(bytes)) != -1) {
                  System.out.println(new String(bytes,0,len));
                  bos.write(bytes,0,len);//写入字符串
                  bos.flush();//刷新该流的缓冲,写入文件
              }
              
              //释放资源
              bis.close();
              bos.close();
              
      • c. 转换流 (字符流) = 字节流 + 编码表
        //指定编码为UTF-8的字符输出流
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("source.txt"),"UTF-8");
        
        //指定编码为UTF-8的字符输入流
        InputStreamReader isr = new InputStreamReader(new FileInputStream("target.txt"),"UTF-8");
        
        /* 
        常见的编码表:
        		ASCII : 美国标准信息交换码, 用一个字节的7位表示数据
        		ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII
        		GB2312 : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII
        		UTF-8 : 是一种可变长度的字符编码, 用1-3个字节表示数据, 又称为万国码, 兼容ASCII用在网页上可以
        				统一页面中的中文简体繁体和其他语言的显示.
        */
        
      • d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
        • d1  Reader 字符流输入超类
          • d1.1  InputStreamReader 用 默认/指定 编码读数据
            //指定输入流 目标文件和字符集 ,如果不指定字符集则按照默认编码表 (java7=GBK,java8=UTF-8)
            InputStreamReader isr = new InputStreamReader(new FileInputStream(""),"GBK");
            
            • d1.1.1  FileReader ↓作为BufferedReader构造器的参数使用↓
              //转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流InputStreamReader提供了对应的子类InputStreamReader
              /*
                (子类)FileWriter:用来写入字符文件的便捷类
                (父类)OutputStreamWriter: FileWriter + 默认编码表(java7=GBK,java8=UTF-8)
               
                (子类)FileReader:用来读取字符文件的便捷类
                (父类)InputStreamReader: FileReader + 默认编码表(java7=GBK,java8=UTF-8)
              */
              
              //封装数据源
              FileReader fr = new FileReader("source.txt");
              //封装目的地
              FileWriter fw = new FileWriter("target.txt");
              
          • e1. 字符缓冲区流BufferedReader 最常用
            //指定输入流
            BufferedReader br = new BufferedReader(new FileReader("source.txt"));
            //指定输出流
            BufferedWriter bw = new BufferedWriter(new FileWriter("target.txt"));
            
            //a.一次读取一个字符
            int ch;
            while ((ch = br.read()) != -1) {
                //对应Unicode编码10进制的值 查询工具 => 
                //http://www.mytju.com/classcode/tools/encode_gb2312.asp
            	System.out.println(ch);
            }
            
            //b.一次读取多个字符【注意 换行符也算字符】
            char[] bytes = new char[1024];//一次取出1024个字符
            int len;//代表有效个数
            while((len = br.read(bytes)) != -1)
            {
                System.out.print(new String(chars, 0, len));//注意是print不是println
            }
            
            //c.读取一整行字符串【注意 不包括换行符,需要手动newLine()换行】
            //String line = br.readLine();
            String line;//代表一整行字符串
            //按行读取整篇文章的内容
            while((line = br.readLine()) != null)
            {
                System.out.println(line);
            }
            
            //释放资源
            br.close();
            bw.close();
            
        • d2  Writer 字符流输出超类
          • d2.1  PrintWriter
          • d2.2  OutputStreamWriter 用 默认/指定 编码写数据
            //指定输出流 目标文件和字符集,如果不指定字符集则按照默认编码表 (java7=GBK,java8=UTF-8)
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("target.txt"),"GBK");
            
            • d2.2.1  FileWriter ↓作为BufferedWriter构造器的参数使用↓
              //转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流OutputStreamWriter提供了对应的子类FileWriter
              /*
                (子类)FileWriter:用来写入字符文件的便捷类
                (父类)OutputStreamWriter: FileWriter + 默认编码表(java7=GBK,java8=UTF-8)
               
                (子类)FileReader:用来读取字符文件的便捷类
                (父类)InputStreamReader: FileReader + 默认编码表(java7=GBK,java8=UTF-8)
              */
              
              //封装数据源
              FileReader fr = new FileReader("source.txt");
              //封装目的地
              FileWriter fw = new FileWriter("target.txt");
              
          • e2. 字符缓冲区流BufferedWriter 最常用
            //指定输入流
            BufferedReader br = new BufferedReader(new FileReader("br.txt"));
            //指定输出流
            BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
            
            //a.一次读取一个字符
            int ch;
            while ((ch = br.read()) != -1) {
            	bw.write(ch);//写入字符串
            	bw.flush();//刷新该流的缓冲,写入文件
            }
            
            //b.一次读取多个字符【注意 换行符也算字符】
            char[] bytes = new char[1024];//一次取出1024个字符
            int len;//代表有效个数
            while((len = br.read(bytes)) != -1)
            {
                bw.write(new String(bytes, 0 , len));//写入字符串
                bw.newLine();
                bw.flush();//刷新该流的缓冲,写入文件
            }
            
            //c.读取一整行字符串【注意 不包括换行符,需要手动newLine()换行】
            //String line = br.readLine();
            String line;//代表一整行字符串
            //按行读取整篇文章的内容
            while((line = br.readLine()) != null)
            {
                bw.write(line);//写入字符串
                bw.newLine();
                bw.flush();//刷新该流的缓冲,写入文件
            }
            
            //释放资源
            br.close();
            bw.close();
            
    • 按流向分类
      • 输入流 : 用来读取数据的
      • 输出流 : 用来写出数据的

3.1 字节流


a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)

  • InputStream 字节流输入超类
  • FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
    • b. 字节缓冲区流BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
  • OutPutStream 字节流输出超类
    • FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
      • b 字节缓冲区流BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码

3.1.1 FOS与FIS

  • 简写说明
    • FIS = FileInPutStream
    • FOS = FileOutPutStream

  • 字节流写数据
    • OutputStream:此抽象类是表示输出字节流的所有类的超类
    • FileOutputStream:文件输出流是用于将数据写入 File

  • 字符流读数据
    • OutputStream:此抽象类是表示输出字节流的所有类的超类
    • FileOutputStream:文件输出流是用于将数据写入 File

  • 构造方法
    //创建一个向具有指定名称的文件中写入数据的输出文件流。
    FileOutputStream(String name)
    

  • 字节流写数据的步骤
    • A:创建字节输出流对象
    • B:调用写数据的方法 write(int);
    • C:释放资源 close()

案例代码八字节流FileOutputStream写出数据

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction 字节流FileOutputStream写出数据
 *
 *  字节流:
 *   	InputStream		字节输入流
 *   	OutputStream	字节输出流
 *  字符流:
 *  	Reader	字符输入流
 *   	Writer	字符输出流
 *
 *  字节流写数据
 *  	 OutputStream:此抽象类是表示输出字节流的所有类的超类
 *  	 FileOutputStream:文件输出流是用于将数据写入 File
 *
 * 构造方法:
 *  	 FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流。
 *
 * 字节流写数据的步骤:
 *  		A:创建字节输出流对象
 *  		B:调用写数据的方法
 *   		C:释放资源
 */
public class Demo8FileOutputStream {
    public static void main(String[] args) throws IOException {
        //创建字节输出流对象 throws FileNotFoundException
        FileOutputStream fos = new FileOutputStream("a.txt");
        /*
            创建字节输出流对象做了3件事
            a. 调用File类创建了文件
            b. 创建字节输出流对象
            c. 让fos这个对象指向a.txt这个文件
         */

        //throws IOException (包含FileNotFoundException)
        System.out.println("fos.write");
        //FileOutputStream.write(int b); b = 十进制的unicode编码
        fos.write(65);//A
        fos.write(66);//B
        System.out.println("写入结束");
        //关闭IO流,回收系统资源
        fos.close();
    }
}

3.1.2 FOS写数据的三种方式

  • 方法摘要
      //a.写出数据的三个方法
      //一次写一个字节
      public void write(int b)
      
      //一次写一个字节数组
      public void write(byte[] b)
      
      //一次写一个字节数组的一部分
      public void write(byte[] b,int off,int len)
      
      //b.String类中的方法
      //将字符串转换为字节数组
      byte[] getBytes()
    

案例代码九字节流FileOutputStream写数据的三种方式

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction 字节流FileOutputStream写数据的三种方式
 *
 * A.构造方法的三种方式:
 *      1. FileOutputStream(String name)
 *      2. FileOutPutStream(File file)
 *      3. FileOutPutStream(new File(xxx))
 *      4. FileOutputStream(xxx,true) //true=追加数据,默认为false,清空后重新写入数据
 *
 * B.写数据的三种方式: throws IOException
 *      1. FileOutputStream.write(int b):一次写一个字节
 *      2. FileOutputStream.write(byte[] b):一次写一个字节数组
 *      3. FileOutputStream.write(byte[] b,inf off,int len):一次写一个字节数组的一部分
 *
 * 字节流写数据的步骤:
 *      a: 创建字节输出流对象 new FileOutPutStream(String name)
 *      b: 调用写数据的方法
 *      c: 释放资源 fos.close()
 */
public class Demo9FileOutPutStreamMethod {
    public static void main(String[] args) throws IOException {
        //A1. FileOutputStream构造方式1 FileOutputStream(String name)
        FileOutputStream fos1 = new FileOutputStream("b.txt");

        //A2. FileOutputStream构造方式2 FileOutPutStream(File file)
        File f2 = new File("c.txt");
        FileOutputStream fos2 = new FileOutputStream(f2);

        //A3. FileOutPutStream构造方式3 FileOutPutStream(new File(xxx))
        FileOutputStream fos3 = new FileOutputStream(new File("d.txt"));

        //B1. 写入数据方式1 FileOutputStream.write(int b):一次写一个字节
        //throws IOException
        fos1.write(65);

        //B2. 写入数据方式2 FileOutputStream.write(byte[] b):一次写一个字节数组
        byte[] bys = {65, 66, 67, 68, 69};
        fos2.write(bys);

        //B3. 写入数据方式3 FileOutputStream.write(byte[] b,inf off,int len):一次写一个字节数组的一部分
        fos3.write("ABCDE".getBytes(), 0, 3);

        File path = new File("");
        System.out.println("文件路径:" + path.getAbsolutePath());

        //释放资源
        fos1.close();
        fos2.close();
        fos3.close();
    }
}

3.1.3 FOS如何实现换行和追加写数据

FIS = FileInPutStream


  • 不同的操作系统,针对换行的符号识别是不一样的。
    • windows:\r\n
    • linux:\n
    • mac:\r

  • 如何实现数据的追加写入?
    • 用构造方法带第二个参数是true的情况即可

案例代码十字节流FileOutputStream写数据换行、追加

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction 字节流FileOutputStream写数据换行、追加
 */
public class Demo10FileOutPutStreamNewLine {
    public static void main(String[] args) throws IOException {
        //先清空文件
        FileOutputStream clear = new FileOutputStream("b.txt");
        clear.write("".getBytes());

        //如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处(默认为false)
        FileOutputStream fos = new FileOutputStream("b.txt", true);

        //循环写入三次hello和换行
        for (int i = 0; i < 3; i++) {
            fos.write("hello".getBytes());
            fos.write("\r\n".getBytes());
        }

        System.out.println("文件路径为:" + new File("").getAbsolutePath());

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

3.1.4 FOS写数据加入异常处理

FIS = FileInPutStream

  • try…catch.finally
      //格式
      try{
      	可能发生问题的代码
      }catch(){
      	处理异常代码
      }finally{
      	一定会被执行的代码.   // 通常用于释放资源, 做善后的动作
      }
    

案例代码十一字节流FileOutputStream写数据加入异常处理

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction 字节流FileOutputStream写数据加入异常处理
 *
 * 格式:
 * 		try{
 * 			可能发生问题的代码
 *      }catch(){
 * 	        处理异常代码
 *      }finally{
 * 		    一定会被执行的代码.   // 通常用于释放资源, 做善后的动作
 *      }
 */
public class Demo11FOSTryCatch {
    public static void main(String[] args) {
        //fos放在外面是为了在finally中可以关闭
        FileOutputStream fos = null;

        try {
            fos = new FileOutputStream("d.txt");
            fos.write("hello".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                //释放资源
                try {
                    fos.close();
                } catch (IOException e) {
                    System.out.println("fos关闭失败");
                }
            }
        }
    }
}

3.1.5 FIS读数据方式1一次读取一个字节

FIS = FileInPutStream

  • 字节流读数据的步骤
    • A : 创建字节输入流对象
    • B : 调用读数据的方法
    • C : 释放资源

案例代码十二字节流FileInputStream读数据方式1

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction 字节流FileInputStream读数据方式1
 *
 * 读数据方式1: 一次读取一个字节
 *     int by;
 *     while((by=fis.read())!=-1) {
 * 			System.out.print((char)by);
 *     }
 *
 * 读数据方式2: 一次读取一个字节数组
 *      //数组长度为1024或者1024的整数倍
 *      byte[] bys = new byte[1024];
 * 		int len;
 * 		//将数据读取到数组中, 并用len记录读取到的有效字节个数
 * 		while((len=fis.read(bys))!=-1) {
 * 	        //byte --> String	new String(bys,0,len)
 * 			System.out.print(new String(bys,0,len));
 *      }
 */
public class Demo12FileInputStreamType1 {
    public static void main(String[] args) throws IOException {
        System.out.println("读数据方式1: 一次读取一个字节");
        //创建字节输入流对象
        FileInputStream fis1 = new FileInputStream("b.txt");//刚才在b.txt写入了3行hello

        for (int i = 0; i < 200; i++) {
            /*
                104 => h
                101 => e
                108 => l
                108 => l
                111 => o
                13  => \r
                10  => \n
                ...
                -1  => 没有数据
                -1  => 没有数据
                -1  => 没有数据
                ...
             */
            System.out.println(fis1.read());
        }

        System.out.println("改进为循环方式打印");
        FileInputStream fis2 = new FileInputStream("b.txt");//刚才在b.txt写入了10行helloWorld
        int by;
        //如果fis.read不等于-1说明还有数据,则继续读文件
        while ((by = fis2.read()) != -1) {
            /*
                hello
                hello
                hello
                hello
                hello
                hello
                hello
                hello
                hello
                hello
             */
            System.out.print((char) by);
        }
    }
}

3.1.6 FIS读数据方式2一次读取一个字节数组

  • 方法摘要
      /*从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中
      返回值是读入缓冲区的字节总数,也就是实际的读取个数
      如果因为已经到达文件末尾而没有更多的数据,则返回 -1。*/
      public int read(byte[] b):
    

案例代码十三字节流FileInputStream读数据方式2

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/23
 * @introduction FileInputStream读数据方式2
 *
 *  public int read(byte[] b):
 *       从次输入流中将最多b.length 个字节的数据读入一个byte数组中
 *       返回值是读入缓冲区的字节总数
 *
 * 读数据方式1: 一次读取一个字节
 *     int by;
 *     while((by=fis.read())!=-1) {
 * 			System.out.print((char)by);
 *     }
 * byte -> String 通过构造方法转换
 *      String(byte[] bytes)
 *      String(byte[] bytes,int offset,int length)  offset 开始位置;length 截取长度
 *
 * byte数组长度为1024或者1024的整数倍:
 *  1G=1024MB
 *  1MB=1024KB
 *
 * 读数据方式2: 一次读取一个字节数组
 *      //数组长度为1024或者1024的整数倍
 *      byte[] bys = new byte[1024];
 * 		int len;
 * 		//将数据读取到数组中, 并用len记录读取到的有效字节个数
 * 		while((len=fis.read(bys))!=-1) {
 * 	        //byte --> String	new String(bys,0,len)
 * 			System.out.print(new String(bys,0,len));
 *      }
 */
public class Demo13FileInputStreamType2 {
    public static void main(String[] args) throws IOException {
        System.out.println("-----读数据方式2: 一次读取一个字节数组-----");
        FileInputStream fis1 = new FileInputStream("b.txt");//刚才在b.txt写入了3行hello
        //标准代码字符缓冲区bys1长度应为1024或1024的整数倍,这里先用8演示读取的原理
        byte[] bys1 = new byte[8];
        //第一次读取
        int len1 = fis1.read(bys1);
        System.out.println(len1);//8
        /*
            第一次读取: hello
            h
         */
        System.out.println("第一次读取: " + new String(bys1));
        //第二次读取
        len1 = fis1.read(bys1);
        System.out.println(len1);//8
        /*
            第二次读取: ello
            he
         */
        System.out.println("第二次读取: " + new String(bys1));
        //第三次读取
        len1 = fis1.read(bys1);
        System.out.println(len1);//5 => 只读取了5个字符,就返回了5
        /*
            第三次读取: llo

            he
         */
        /* 解析:
              文件内容为
              hello\r\n
              hello\r\n
              hello\r\n

              第一次读取8个字节为 [h] [e] [l] [l] [o] [\r][\n] [h]
              第二次读取8个字节为 [e] [l] [l] [o] [\r][\n] [h] [e]
              第三次读取8个字节为 [l] [l] [o] [\r][\n]
              但数组写入方式是每次覆盖前一次的,所以第二次写入的还保留着
              bys[5] = \r
              bys[6] = h
              bys[7] = e
              所以第三次数组内容为  [l] [l] [o] [\r][\n][\n] [h] [e]
              所以才会打印出以上内容
         */
        System.out.println("第三次读取: " + new String(bys1));
        //第四次读取
        len1 = fis1.read(bys1);
        System.out.println(len1);//-1 => 表示没有数据了



        System.out.println("-----改进为循环读取文件-----");
        //创建字节输入流对象
        FileInputStream fis2 = new FileInputStream("b.txt");
        byte[] bys2 = new byte[1024]; //1024或者1024的整数倍
        int len2;
        //将数据读取到数组中, 并用len记录读取到的有效字节个数
        while ((len2 = fis2.read(bys2)) != -1) {
            //只读取到len的长度,否则会出现
            System.out.print(new String(bys2, 0, len2));
        }
        System.out.println("\r\n读取结束");
        fis2.close();
    }
}

3.1.7 字节流练习之复制文本文件

  • 需求
    • 拷贝文本文件

  • 分析
    • 第一步: 创建输入输出流对象关联数据源和数据目的
    • 第二步: 定义字节数组,为了提高效率
    • 第三步: 将数据通过while循环不断读取到字节数组中
    • 第四步: 将数据从字节数组中取出并写出
    • 第五步: 释放资源

  • 待拷贝的文本文件(d:\窗里窗外.txt)

    《窗里窗外》是林青霞近5年所写的46篇散文的结集,虽是旧作,但该书记录她19岁以《窗外》成名后多方面的人生经历,字字真实深刻。《窗里窗外》共分为六个章节:“戏”里说的是她的出道故事、拍戏的甘苦、对于作品的内心话;“亲”谈她的家人亲情;“友”则书写她与挚友的交往,细谈她与三毛、黄霑、张国荣、龙应台、琼瑶、徐克等人的往来互动;“趣”是她的生活记趣,有旅行见闻,也有她与影迷的邂逅;“缘”则书写她一生难忘的相遇,像是和记者的友谊,和季羡林的会面之缘;“悟”里记录了她对人生的体悟和感动,以及她向圣严法师求道的故事。此外,书中还完整收录了林青霞一些未公开的照片。
    第1节:人生小语(1)…


案例代码十四字节流练习之复制文本文件

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/25
 * @introduction 字节流练习之复制文本文件
 *
 * 需求:
 *      拷贝文本文件
 * 分析:
 *      第一步: 创建输入输出流对象关联数据源和数据目的
 *      第二步: 定义字节数组,为了提高效率
 *      第三步: 将数据通过while循环不断读取到字节数组中
 *      第四步: 将数据从字节数组中取出并写出
 *      第五步: 释放资源
 */
public class Demo14FileCopy {
    public static void main(String[] args) throws IOException {
        //封装数据源
        FileInputStream fis = new FileInputStream("d:" + File.separator + "窗里窗外.txt");
        //封装目的地(目标文件,追加true清空重写false)
        FileOutputStream fos = new FileOutputStream("d:" + File.separator + "林青霞.txt", false);

        //a.一次写入一个字符
        int by;
        while ((by = fis.read()) != -1) {
            fos.write(by);
        }

        //b.一次写入一个字符数组
        byte[] bys = new byte[1024];
        int len;
        while ((len = fis.read(bys)) != -1) {
            fos.write(bys, 0, len);
        }

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

3.2.8 字节流练习之复制图片
  • 思路
    • 同理3.1.7案例

案例代码十五字节流练习之复制图片

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/25
 * @introduction 字节流练习之复制图片
 */
public class Demo15PictureCopy {
    public static void main(String[] args) throws IOException {
        //封装数据源
        FileInputStream fis1 = new FileInputStream("d:" + File.separator + "01_字节流体系图.jpg");
        FileInputStream fis2 = new FileInputStream("d:" + File.separator + "01_字节流体系图.jpg");
        //封装目的地
        FileOutputStream fos1 = new FileOutputStream("d:" + File.separator + "copy1.jpg");
        FileOutputStream fos2 = new FileOutputStream("d:" + File.separator + "copy2.jpg");

        //读写数据
        int by;
        //方式1:一次读取一个字节
        //如果fis.read不等于-1说明还有数据,则继续读文件
        while ((by = fis1.read()) != -1) {
            fos1.write(by);
        }

        //方式2:一次读取一个字节数组
        byte[] bys = new byte[1024];
        int len;
        while ((len = fis2.read(bys)) != -1) {
            fos2.write(bys, 0, len);
        }

        //释放资源
        fis1.close();
        fis2.close();
        fos1.close();
        fos2.close();
    }
}

3.2 字节缓冲区流


a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)

  • InputStream 字节流输入超类
  • FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
    • b. 字节缓冲区流BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
  • OutPutStream 字节流输出超类
    • FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
      • b 字节缓冲区流BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码

3.2.1 概述

  • 作用
    • 字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果
    • java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流

  • 字节缓冲流
    • BufferedOutputStream : 字节缓冲输出流
    • BufferedInputStream : 字节缓冲输入流

  • 为什么字节缓冲流的构造方法需要传入一个OutputStream
    • 字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作

案例代码十六字节缓冲流概述

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/04/27
 * @introduction 字节缓冲流
 *
 * 构造方法
 *      BufferedOutputStream(OutputStream out)
 *      BufferedInputStream(InputStream in)
 *
 * 方法摘要
 *      BufferedOutputStream.write(byte b[])
 */
public class Demo16BufferedOutputStream {
    public static void main(String[] args) throws IOException {
        //指定字符缓冲输出流

        // FileOutputStream fos = new FileOutputStream("a.txt");
        // BufferedOutputStream bos = new BufferedOutputStream(fos);
        // 上面的两句等价于下面的这一句
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));

        byte[] bytes = "hello".getBytes();
        bos.write(bytes);//写入字符数组
        bos.close();

        //指定字符缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
        //方式1 : 一次读取一个字节
        int by;
        while ((by = bis.read()) != -1) {
            System.out.println((char) (by));
        }

        //方式2 : 一次读取一个字节数组
        byte[] bys = new byte[1024];
        int len;
        while ((len = bis.read(bys)) != -1) {
            System.out.println(new String(bys, 0, len));
        }

        //释放资源
        bos.close();
        bis.close();
    }
}

3.2.2 四种方式复制图片效率测试

  • 方法摘要

    //返回以毫秒为单位的当前时间。
    public static long currentTimeMillis()
    

案例代码十七字节流&字节缓冲区流四种方式复制AVI并测试效率

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/04/27
 * @introduction 字节流&字节缓冲区流四种方式复制AVI并测试效率 
 *
 * 源文件: d:\\复制视频.avi
 * 大小: 34904KB
 *
 * method1: 基本字节流,一次读取一个字节    => method1.avi => 198001毫秒
 * method2: 基本字节流,一次读写一个字节数组 => method2.avi => 278毫秒
 * method3: 缓冲字节流,一次读取一个字节    => method3.avi => 384毫秒
 * method4: 缓冲字节流,一次读写一个字节数组 => method4.avi => 190毫秒
 *
 * 结论: method4 > method2 > method3 > method1
 */
public class Demo17BufferedOutputStreamCopyAVITest {
    public static void main(String[] args) throws IOException {
        //记录method1时间
        long start1 = System.currentTimeMillis();
        method1();//method1共耗时198001毫秒
        long end1 = System.currentTimeMillis();
        System.out.println("method1共耗时" + (end1 - start1) + "毫秒");

        //记录method2时间
        long start2 = System.currentTimeMillis();
        method2();//method2共耗时278毫秒
        long end2 = System.currentTimeMillis();
        System.out.println("method2共耗时" + (end2 - start2) + "毫秒");

        //记录method3时间
        long start3 = System.currentTimeMillis();
        method3();//method3共耗时384毫秒
        long end3 = System.currentTimeMillis();
        System.out.println("method3共耗时" + (end3 - start3) + "毫秒");

        //记录method4时间
        long start4 = System.currentTimeMillis();
        method4();//method4共耗时190毫秒
        long end4 = System.currentTimeMillis();
        System.out.println("method4共耗时" + (end4 - start4) + "毫秒");
    }

    //method1: 基本字节流,一次读取一个字节    => method1.avi
    private static void method1() throws IOException {
        //封装数据源
        FileInputStream fis = new FileInputStream("d:\\复制视频.avi");
        //封装目的地
        FileOutputStream fos = new FileOutputStream("d:\\method1.avi");

        int by;
        while ((by = fis.read()) != -1) {
            fos.write(by);
        }
        //释放资源
        fis.close();
        fos.close();
    }

    //method2: 基本字节流,一次读写一个字节数组 => method2.avi
    private static void method2() throws IOException {
        //封装数据源
        FileInputStream fis = new FileInputStream("d:\\复制视频.avi");
        //封装目的地
        FileOutputStream fos = new FileOutputStream("d:\\method2.avi");

        byte[] bys = new byte[1024];
        int len;
        while ((len = fis.read(bys)) != -1) {
            fos.write(bys, 0, len);
        }
        //释放资源
        fis.close();
        fos.close();
    }

    //method3: 缓冲字节流,一次读取一个字节    => method3.avi
    private static void method3() throws IOException {
        //封装数据源
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制视频.avi"));
        //封装目的地
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\method3.avi"));

        int by;
        while ((by = bis.read()) != -1) {
            bos.write(by);
        }
        //释放资源
        bis.close();
        bos.close();
    }

    //method4: 缓冲字节流,一次读写一个字节数组 => method4.avi
    private static void method4() throws IOException {
        //封装数据源
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制视频.avi"));
        //封装目的地
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\method4.avi"));

        byte[] bys = new byte[1024];
        int len;
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
        }
        //释放资源
        bis.close();
        bos.close();
    }
}

3.3 转换流


c. 转换流 (字符流) = 字节流 + 编码表


  • 转换流出现的原因
    • 由于字节流操作中文不是特别方便,所以,java就提供了转换流
    • 转换流 = 字节流 + 编码表

  • 字节流读数据可能出现问题
    • 字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。
    • 文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。
    • 汉字存储的规则
      • 左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。

案例代码十八转换流出现的原因

package com.groupies.base.day13;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;

/**
 * @author GroupiesM
 * @date 2021/04/27
 * @introduction 转换流出现的原因
 *
 * 转换流出现的原因
 *      由于字节流操作中文不是特别方便,所以,java就提供了转换流
 *      转换流 = 字节流 + 编码表
 *
 * 字节流读数据可能出现问题
 *      字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。
 *      文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。
 *
 * 汉字存储的规则 : 左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。
 *
 * a.txt内容:
 *      hi
 *      张三
 */
public class Demo18FileInputStream {
    public static void main(String[] args) throws IOException {
        //基本字节流一次读取一个字节
        FileInputStream fis = new FileInputStream("a.txt");

        int by;
        while ((by = fis.read()) != -1) {
            /*
                hi
                å¼ ä¸‰
             */
            System.out.print((char) by);
        }
        //释放资源,刷新缓冲区
        fis.close();

        System.out.println("");
        String s = "你";
        byte[] bys = s.getBytes("GBK");
        /*常见的编码表测试 中文"你"转换为字节数组
            UTF-8          => [-28, -67, -96]  => JDK8中不指定编码则默认为 UTF-8
            GBK/GB2312     => [-60, -29]       => JDK7中不指定编码则默认为 GBK/GB2312
            ISO-8859-1     => [63]
            ASCII          => [63]
            UNICODE/UTF-16 => [-2, -1, 79, 96] => UNICODE 默认使用的是UTF-16的实现方式
         */
        System.out.println(Arrays.toString(bys));
    }
}

3.3.1 什么是编码表

  • 编码表
    • 由字符及其对应的数据组成的一张表
      ASCII
      	‘a’	97A65048
      

  • 常见的编码表

    • ASCII : 美国标准信息交换码, 用一个字节的7位表示数据;(ASCII 0-126)
    • ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII;
    • GB2312/GBK : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII;
    • UTF-8 : 使用一到四个字节来编码一个码点。, 兼容ASCII;用在网页上可以统一页面中的中文简体繁体和其他语言的显示;
    • UNICODE : 为世界上所有字符都分配了一个唯一的数字编号,又称万国码;有多种实现方案(UTF-32 、UTF-16 、UTF-8)。

  • 乱码问题
    • 针对同一个数据, 采用的编码和解码不一致导致

      3.1_14 JavaSE入门 P13 【其他】异常,File,IO,字节(符)流,字节(符)缓冲流,转换流_第1张图片


案例代码十九遍历编码表_int转char

package com.groupies.base.day13;

/**
 * @author GroupiesM
 * @date 2021/04/27
 * @introduction 遍历编码表_int转char
 *
 * 遍历ASCII码表 0~255
 */
public class Demo19ASCIIFor {
    public static void main(String[] args) {
        int count = 0;
        for (int i = 8; i < 127; i++) {
            //每打印5个换行一次
            if (count == 5) {
                System.out.println("");
                count = 0;
            }
            //13换行一次,否则CR归位键会回到行最左侧位置,导致控制台打印的10-12被吞掉
            if (i == 13) {
                System.out.println("");
            }
            char ch = (char) i;
            System.out.print("【" + ch + " = " + i + "】\t");
            count++;
        }
    }
    /* 8 为/b 退格
       13 为\r 归为 导致 【 符号被吞掉
        【  = 0】	【 = 1】	【 = 2】	【 = 3】	【 = 4】
        【 = 5】	【 = 6】	【 = 7】	 = 8】	【	 = 9】
        【
         = 10】	【 = 11】	【 = 12】
         = 13】	【 = 14】
        【 = 15】	【 = 16】	【 = 17】	【 = 18】	【 = 19】
        【 = 20】	【 = 21】	【 = 22】	【 = 23】	【 = 24】
        【 = 25】	【 = 26】	【 = 27】	【 = 28】	【 = 29】
        【 = 30】	【 = 31】	【  = 32】	【! = 33】	【" = 34】
        【# = 35】	【$ = 36】	【% = 37】	【& = 38】	【' = 39】
        【( = 40】	【) = 41】	【* = 42】	【+ = 43】	【, = 44】
        【- = 45】	【. = 46】	【/ = 47】	【0 = 48】	【1 = 49】
        【2 = 50】	【3 = 51】	【4 = 52】	【5 = 53】	【6 = 54】
        【7 = 55】	【8 = 56】	【9 = 57】	【: = 58】	【; = 59】
        【< = 60】	【= = 61】	【> = 62】	【? = 63】	【@ = 64】
        【A = 65】	【B = 66】	【C = 67】	【D = 68】	【E = 69】
        【F = 70】	【G = 71】	【H = 72】	【I = 73】	【J = 74】
        【K = 75】	【L = 76】	【M = 77】	【N = 78】	【O = 79】
        【P = 80】	【Q = 81】	【R = 82】	【S = 83】	【T = 84】
        【U = 85】	【V = 86】	【W = 87】	【X = 88】	【Y = 89】
        【Z = 90】	【[ = 91】	【\ = 92】	【] = 93】	【^ = 94】
        【_ = 95】	【` = 96】	【a = 97】	【b = 98】	【c = 99】
        【d = 100】	【e = 101】	【f = 102】	【g = 103】	【h = 104】
        【i = 105】	【j = 106】	【k = 107】	【l = 108】	【m = 109】
        【n = 110】	【o = 111】	【p = 112】	【q = 113】	【r = 114】
        【s = 115】	【t = 116】	【u = 117】	【v = 118】	【w = 119】
        【x = 120】	【y = 121】	【z = 122】	【{ = 123】	【| = 124】
        【} = 125】	【~ = 126】
     */
}

3.3.2 String类的编解码

  • 方法摘要

    • 编码 : 把看得懂的变成看不懂的

      //使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 
      public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
      
    • 解码 : 把看不懂的变成看得懂的

      //通过使用指定的 charset解码指定的 byte 数组,构造一个新的 String。
      public String(byte[] bytes, String charsetName)
      

  • 重点强调 : 编码和解码的方式需要一致

案例代码二十String 类的编解码

package com.groupies.base.day13;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

/**
 * @author GroupiesM
 * @date 2021/04/28
 * @introduction String 类的编解码
 *
 * 方法摘要
 *      a.编码 : 把看得懂的变成看不懂的
 *          使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
 *          public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
 *
 *      b.解码 : 把看不懂的变成看得懂的
 *          通过使用指定的 charset解码指定的 byte 数组,构造一个新的 String。
 *          public String(byte[] bytes, String charsetName)
 *
 * 常见的编码表测试 中文"你"转换为字节数组
 *      UTF-8          => [-28, -67, -96]  => JDK8中不指定编码则默认为 UTF-8
 *      GBK/GB2312     => [-60, -29]       => JDK7中不指定编码则默认为 GBK/GB2312
 *      ISO-8859-1     => [63]
 *      ASCII          => [63]
 *      UNICODE/UTF-16 => [-2, -1, 79, 96] => UNICODE 默认使用的是UTF-16的实现方式
 */
public class Demo20StringEncodeDecode {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //定义一个字符串
        String s = "你好";

        //a.编码 getBytes => throws UnsupportedEncodingException 不支持的编码异常
        byte[] encodeGBK = s.getBytes("GBK");
        System.out.println(Arrays.toString(encodeGBK));//[-60, -29, -70, -61]

        byte[] encodeUTF = s.getBytes("UTF-8");
        System.out.println(Arrays.toString(encodeUTF));//[-28, -67, -96, -27, -91, -67]

        //b.解码
        byte[] bytesGBK = {-60, -29, -70, -61};
        String decodeGBK = new String(bytesGBK);
        //Java8默认编解码字符集为UTF8 用UTF8解码 GBK编码的字节码文件就会出现乱码
        System.out.println(decodeGBK);//���
        String decodeGBKAgain = new String(bytesGBK, "GBK");
        //指定用GBK解码
        System.out.println(decodeGBKAgain);//你好


        byte[] bytesUTF = {-28, -67, -96, -27, -91, -67};
        //不指定解码字符集,Java8环境默认使用UTF8字符集进行编解码,刚好和字节数组匹配
        String decodeUTF = new String(bytesUTF);
        System.out.println(decodeUTF);//你好
    }
}

3.3.3 字符流Stream的编解码(写入文件)

  • OutputStreamWriter 字符输出流
     //根据【默认编码】把字节流的数据转换为字符流
     public OutputStreamWriter(OutputStream out)
    
     //根据【指定编码】把字节流数据转换为字符流
     public OutputStreamWriter(OutputStream out,String charsetName)
    

  • InputStreamReader 字符输入流
     //用【默认编码】读数据 
     public InputStreamReader(InputStream in)
    
     //用【指定编码】读数据
     public InputStreamReader(InputStream in,String charsetName)
    

  • IDEA设置文件编码

    查看文件结果显示是乱码,原因是输出时指定编码为GBK,java8查看默认编码为UTF-8,需要修改文件解码格式

    选择 File => File Properties => File Encoding

    3.1_14 JavaSE入门 P13 【其他】异常,File,IO,字节(符)流,字节(符)缓冲流,转换流_第2张图片

    选择GBK

    3.1_14 JavaSE入门 P13 【其他】异常,File,IO,字节(符)流,字节(符)缓冲流,转换流_第3张图片

    重新查看文件内容,显示已正常

    3.1_14 JavaSE入门 P13 【其他】异常,File,IO,字节(符)流,字节(符)缓冲流,转换流_第4张图片


案例代码二十一Stream转换流的编解码

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/04/28
 * @introduction Stream转换流的编解码
 *
 * OutputStreamWriter 字符输出流
 *    public OutputStreamWriter(OutputStream out)  根据【默认编码】把字节流的数据转换为字符流
 *    public OutputStreamWriter(OutputStream out,String charsetName) 根据【指定编码】把字节流数据转换为字符流
 *
 * InputStreamReader** 字符输入流
 *    public InputStreamReader(InputStream in)  用【默认编码】读数据
 *    public InputStreamReader(InputStream in,String charsetName)  用【指定编码】读数据
 */
public class Demo21StreamEncodeDecode {
    public static void main(String[] args) throws IOException {
        //指定输出流 目标文件和字符集
        OutputStreamWriter oswGBK = new OutputStreamWriter(new FileOutputStream("osw.txt"), "GBK");
        //指定输入流 目标文件和字符集
        InputStreamReader isrGBK = new InputStreamReader(new FileInputStream("osw.txt"), "GBK");
        InputStreamReader isrUTF = new InputStreamReader(new FileInputStream("osw.txt"), "utf-8");

        //调用写数据的方法
        oswGBK.write("你好");
        oswGBK.flush();//刷新缓冲流(执行一次写入)

        //用GBK解码GBK文本
        int byGBK;
        while ((byGBK = isrGBK.read()) != -1) {
            System.out.print((char) byGBK);//你好
        }

        System.out.println("");

        //用UTF-解码GBK文本
        int byUTF;
        while ((byUTF = isrUTF.read()) != -1) {
            System.out.print((char) byUTF);//���
        }

        //释放资源
        oswGBK.close();
        isrGBK.close();
        isrUTF.close();
    }
}

3.4 字符流


d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)

  • Reader 字符流输入超类
    • InputStreamReader
      • FileReader ↓作为BufferedReader构造器的参数使用↓
    • e. 字符缓冲区流BufferedReader 最常用
  • Writer 字符流输出超类
    • PrintWriter
    • OutputStreamWriter
      • FileWriter ↓作为BufferedWriter构造器的参数使用↓
    • e. 字符缓冲区流BufferedWriter 最常用

3.4.1 复制Java文件

  • 需求
    • 把项目目录下的StringDemo.java内容复制到项目目录下的Copy.java中

  • 三种方式
    • InputStreamReader & OutputStreamWriter (字符流方式 见3.4.1) 2153毫秒
    • FileReader & FileWriter (字符流方式 见3.4.1) 1957毫秒
    • BufferedReader & BufferedWriter (字符缓冲区流方式 见3.5.2) 2840毫秒

案例代码二十二字符流 复制java文件

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/04/28
 * @introduction 字符流 复制Java文件
 *
 * 需求 : 把项目目录下的 StringDemo.java内容复制到项目目录下的Copy.java中
 *
 * 三种方式:
 *      √ 1.字符流      InputStreamReader & OutputStreamWriter
 *      √ 2.字符流      FileReader & FileWriter
 *      x 3.字符缓冲区流 BufferedReader & BufferedWriter
 */
public class Demo22StreamCopyJava {
    public static void main(String[] args) throws IOException {
        long start1 = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            method1("StringDemo.java","Copy.java");//method1共耗时2153毫秒
        }
        long end1 = System.currentTimeMillis();
        System.out.println("method1共耗时" + (end1 - start1) + "毫秒");

        long start2 = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            method2("StringDemo.java","Copy.java");
        }
        long end2 = System.currentTimeMillis();
        System.out.println("method2共耗时" + (end2 - start2) + "毫秒");//method2共耗时1957毫秒
    }

    /**
     * @introduction InputStreamReader & OutputStreamWriter
     * 需求 : 把项目目录下的 StringDemo.java内容复制到项目目录下的Copy.java中
     * 数据源 : StringDemo.java---读数据---字符流---InputStreamReader
     * 目的地 : Copy.java---写数据---字符流---OutputStreamWriter
     *
     * @param source 数据源
     * @param target 目标数据
     * @throws IOException
     */
    public static void method1(String source, String target) throws IOException {
        //封装数据源
        InputStreamReader isr = new InputStreamReader(new FileInputStream(source));
        //封装目的地
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(target));

        //读写数据
        //方式1:一次读写一个字符
        /*
        int ch;
        while((ch= isr.read())!=-1){
            osw.write(ch);
        }
        */

        //方式2:一次读写一个字符数组
        char[] chArr = new char[1024];
        int len;
        while ((len = isr.read(chArr)) != -1) {
            osw.write(chArr,0,len);
        }

        //释放资源
        osw.close();
        isr.close();
    }

    /**
     * @introduction 优化method1 FileReader & FileWriter
     * 需求 : 把项目目录下的 StringDemo.java内容复制到项目目录下的Copy.java中(改进版)
     *      转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类
     *
     * (子类)FileWriter:用来写入字符文件的便捷类
     * (父类)OutputStreamWriter: FileWriter + 默认编码表(java7=GBK,java8=UTF-8)
     *
     * (子类)FileReader:用来读取字符文件的便捷类
     * (父类)InputStreamReader: FileReader + 默认编码表(java7=GBK,java8=UTF-8)
     *
     * OutputStreamWriter = FileOutputStream + 默认编码表(java7=GBK,java8=UTF-8)
     * FileWriter = FileOutputStream + 默认编码表(java7=GBK,java8=UTF-8)
     *      构造方法:
     *          FileWriter(String fileName)
     *
     * InputStreamReader = FileInputStream + 默认编码表(java7=GBK,java8=UTF-8)
     * FileReader = FileInputStream + 默认编码表(java7=GBK,java8=UTF-8)
     *      构造方法:
     *          FileReader(String fileName)
     *
     * @param source 数据源
     * @param target 目标数据
     * @throws IOException
     */
    public static void method2(String source, String target) throws IOException {
        //封装数据源
        FileReader fr = new FileReader(source);
        //封装目的地
        FileWriter fw = new FileWriter(target);

        //读写数据
        //方式1:一次读写一个字符
/*        int ch;
        while((ch= fr.read())!=-1){
            fw.write(ch);
        }*/

        //方式2:一次读写一个字符数组
        char[] chArr = new char[1024];
        int len;
        while ((len = fr.read(chArr)) != -1) {
            fw.write(chArr,0,len);
        }

        //释放资源
        fw.close();
        fr.close();
    }
}

3.4.3 OutputStreamWriter写数据的6种方式

  • 方法摘要

    /* @introduction 写一个字符
     * @param c 要写入的字符
     */
    public void write(char c)
        
    /* @introduction 写一个字符
     * @param c 要写入的字符对应码表中int值
     */
    public void write(int c)
    
    /* @introduction 写一个字符数组
     * @param cbuf 要写入的字符数组
     */
    public void write(char[] cbuf)
    
    /* @introduction 写一个字符数组的一部分
     * @param cbuf 要写入的字符数组
     * @param off 起始索引
     * @param len 从起始索引起,写入字符数组长度
     */    
    public void write(char[] cbuf,int off,int len)
        
    /* @introduction 写一个字符串
     * @param str 要写入的字符串
     */    
    public void write(String str)
        
    /* @introduction 写一个字符串的一部分
     * @param str 要写入的字符串
     * @param off 起始索引
     * @param len 从起始索引起,写入字符串长度
     */    
    public void write(String str,int off,int len)
    

案例代码二十三OutputStreamWriter写数据的6种方式

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/04/28
 * @introduction OutputStreamWriter写数据的6种方式
 *
 * a. public void write(char c); 写一个字符
 * b. public void write(int c); 写一个字符
 * c. public void write(char[] cbuf); 写一个字符数组
 * d. public void write(char[] cbuf,int off,int len); 写一个字符数组的一部分
 * e. public void write(String str); 写一个字符串
 * f. public void write(String str,int off,int len); 写一个字符串的一部分
 *
 * void flush():刷新该流的缓冲
 *      调用close();时也会调用flush();但close()后无法继续写入
 *      字节流可以直接写入,但字符流需要刷新缓冲
 *      因为字符会先写入字符流缓冲区(内存),到字符流缓冲区满了才会写入一次文件
 *      缓冲区写满之前需要手动flush()或调用close()才会将缓冲区字符写入目标文件(硬盘)
 *
 */
public class Demo23OutputStreamWriter6Type {
    public static void main(String[] args) throws IOException {
        //创建字符输出流对象 (同时创建文件)
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("target.txt"));

        //a. public void write(char c); 写一个字符
        methodA(osw);//写入一个字符a
        osw.write('\r');//换行

        //b. public void write(int c); 写一个字符
        methodB(osw);//写入一个字符b
        osw.write('\r');//换行

        //c. public void write(char[] cbuf); 写一个字符数组
        methodC(osw);//写入abcde
        osw.write('\r');//换行

        //d. public void write(char[] cbuf,int off,int len); 写一个字符数组的一部分
        methodD(osw);//写入c
        osw.write('\r');//换行

        //e. public void write(String str); 写一个字符串
        methodE(osw);//写入hello
        osw.write('\r');//换行

        //f. public void write(String str,int off,int len); 写一个字符串的一部分
        methodF(osw);//写入lo
        osw.write('\r');//换行

        //释放资源
        osw.close();//关闭此流,关闭前将缓冲区(内存)字符刷新(flush=>写入硬盘)
    }


    /**
     * @introduction OutputStreamWriter写数据方式1:写一个字符
     * @param osw
     * @throws IOException
     */
    public static void methodA(OutputStreamWriter osw) throws IOException {
        //a. public void write(char c); 写一个字符
        osw.write('a');
        //void flush():刷新该流的缓冲
        //osw.flush();
    }

    /**
     * @introduction OutputStreamWriter写数据方式2:写一个字符
     * @param osw
     * @throws IOException
     */
    public static void methodB(OutputStreamWriter osw) throws IOException {
        //b. public void write(int c); 写一个字符
        osw.write(98);
        //void flush():刷新该流的缓冲
        //osw.flush();
    }

    /**
     * @introduction OutputStreamWriter写数据方式3:写一个字符数组
     * @param osw
     * @throws IOException
     */
    public static void methodC(OutputStreamWriter osw) throws IOException {
        char[] chs = {'a', 'b', 'c', 'd', 'e' };
        //c. public void write(char[] cbuf); 写一个字符数组
        osw.write(chs);//写入 abcde
        //void flush():刷新该流的缓冲
        //osw.flush();
    }

    /**
     * @introduction OutputStreamWriter写数据方式4:写一个字符数组的一部分
     * @param osw
     * @throws IOException
     */
    public static void methodD(OutputStreamWriter osw) throws IOException {
        char[] chs = {'a', 'b', 'c', 'd', 'e' };
        //d. public void write(char[] cbuf,int off,int len); 写一个字符数组的一部分
        osw.write(chs, 2, 1);//写入bcd
        //void flush():刷新该流的缓冲
        //osw.flush();
    }

    /**
     * @introduction OutputStreamWriter写数据方式5:写一个字符串
     * @param osw
     * @throws IOException
     */
    public static void methodE(OutputStreamWriter osw) throws IOException {
        String s = "hello";
        //e. public void write(String str); 写一个字符串
        osw.write(s);//写入hello
        //void flush():刷新该流的缓冲
        //osw.flush();
    }

    /**
     * @introduction OutputStreamWriter写数据方式6:写一个字符串的一部分
     * @param osw
     * @throws IOException
     */
    public static void methodF(OutputStreamWriter osw) throws IOException {
        String s = "hello";
        //f. public void write(String str,int off,int len); 写一个字符串的一部分
        osw.write(s, 3, 2);
        //void flush():刷新该流的缓冲
        //osw.flush();
    }
}

3.4.3 InputStreamReader读数据的2种方式

  • 方法摘要

    //一次读取一个字符    
    public int read()
    
    //一次读取一个字符数组
    public int read(char[] cbuf)
    

案例代码二十四InputStreamReader读数据的2种方式

package com.groupies.base.day13;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author GroupiesM
 * @date 2021/04/28
 * @introduction InputStreamReader读数据的2种方式
 *
 * a. public int read(); 一次读取一个字符
 * b. public int read(char[] cbuf); 一次读取一个字符数组
 */
public class Demo24InputStreamReader2Type {
    public static void main(String[] args) throws IOException {
        //创建字符流输入对象
        InputStreamReader isrA = new InputStreamReader(new FileInputStream("a.txt"));
        InputStreamReader isrB = new InputStreamReader(new FileInputStream("a.txt"));
        //a. public int read(); 一次读取一个字符
        methodA(isrA);
        System.out.println("\r\n==========================");
        //b. public int read(char[] cbuf); 一次读取一个字符数组
        methodB(isrB);

        //释放资源
        isrA.close();
        isrB.close();
    }

    /**
     * @introduction InputStreamReader读数据方式1:一次读取一个字符
     * @param isr
     * @throws IOException
     */
    public static void methodA(InputStreamReader isr) throws IOException {
        int ch;
        while ((ch = isr.read()) != -1) {
            System.out.print((char)ch);
        }
    }

    /**
     * @introduction InputStreamReader读数据方式2:一次读取一个字符数组
     * @param isr
     */
    public static void methodB(InputStreamReader isr) throws IOException {
        char[] chs = new char[1024];
        int len;
        while ((len = isr.read(chs)) != -1) {
            System.out.println(new String(chs, 0, len));
        }
    }
}

3.5 字符缓冲区流


d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)

  • Reader 字符流输入超类
    • InputStreamReader
      • FileReader ↓作为BufferedReader构造器的参数使用↓
    • e. 字符缓冲区流BufferedReader 最常用
  • Writer 字符流输出超类
    • PrintWriter
    • OutputStreamWriter
      • FileWriter ↓作为BufferedWriter构造器的参数使用↓
    • e. 字符缓冲区流BufferedWriter 最常用

3.5.1 概述

  • BufferedWriter
    • 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
    • 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
    • 构造方法
      BufferedWriter(Writer out)
      

  • BufferedReader
    • 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
    • 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
    • 构造方法
      BufferedReader(Reader in)
      

案例代码二十五字符缓冲区流概述

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/05/08
 * @introduction 字符缓冲区流概述
 *
 * 	BufferedWriter
 * 		将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
 * 		可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
 * 		构造方法:
 *  	 		BufferedWriter(Writer out)
 * 	BufferedReader
 * 		从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
 *   		可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
 *   		构造方法:
 *  			BufferedReader(Reader in)
 */
public class Demo25Buffered {
    public static void main(String[] args) throws IOException {
		//创建字符缓冲输出流对象
		BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
		//调用写数据的方法
		bw.write("hello");
		//释放资源
		bw.close();

        //创建字符缓冲输入流对象
        BufferedReader br1 = new BufferedReader(new FileReader("BufferedStreamDemo.java"));
        BufferedReader br2 = new BufferedReader(new FileReader("BufferedStreamDemo.java"));

        //方式1:一次读取一个字符
        method1(br1);
        //方式2:一次读取一个字符数组
        method2(br2);

        //释放资源
        br1.close();
        br2.close();
    }

    /**
     * @introduction 方式1:一次读取一个字符
     * @param br
     * @throws IOException
     */
    public static void method1(BufferedReader br) throws IOException {
		int ch;
		while((ch=br.read())!=-1) {
			System.out.print((char)ch);
		}
    }

    /**
     * @introduction 方式2:一次读取一个字符数组
     * @param br
     * @throws IOException
     */
    public static void method2(BufferedReader br) throws IOException {
        char[] chs = new char[1024];
        int len;
        while ((len = br.read(chs)) != -1) {
            System.out.print(new String(chs, 0, len));
        }
    }
}

3.5.2 复制文本文件

  • 需求
    • 把项目目录下的a.txt内容复制到项目目录下的b.txt中
    • 数据源
      • a.txt—读数据—字符流—InputStreamReader—FileReader—BufferedReader
    • 目的地
      • b.txt—写数据—字符流—OutputStreamWriter—FileWriter—BufferedWriter

案例代码二十六字符缓冲区流 复制文本文件

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/04/28
 * @introduction 字符缓冲区流 复制文本文件
 *
 * 需求 : 把项目目录下的a.txt内容复制到项目目录下的b.txt中
 * 数据源 : a.txt---读数据---字符流---InputStreamReader---FileReader---BufferedReader
 * 目的地 : b.txt---写数据---字符流---OutputStreamWriter---FileWriter---BufferedWriter
 */
public class Demo26StreamCopyTXT {
    public static void main(String[] args) throws IOException {
        //封装数据源
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        //封装目的地
        BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

        //读写数据
        char[] chs = new char[1024];
        int len;
        while ((len = br.read(chs)) != -1) bw.write(chs, 0, len);

        //释放资源
        bw.close();
        br.close();
    }
}

3.5.3 复制Java文件

  • 需求

    • 把项目目录下的A.java内容复制到项目目录下的Copy.java中
  • 三种方式

    • InputStreamReader & OutputStreamWriter (字符流方式 见3.4.1) 2153毫秒
    • FileReader & FileWriter (字符流方式 见3.4.1) 1957毫秒
    • BufferedReader & BufferedWriter 2840毫秒

案例代码二十七字符缓冲区流 复制Java文件

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/05/08
 * @introduction 字符缓冲区流复制Java文件
 *
 * 需求 : 把项目目录下的StringDemo.java内容复制到项目目录下的Copy.java中
 *
 * 三种方式:
 *      x 1.字符流      InputStreamReader & OutputStreamWriter
 *      x 2.字符流      FileReader & FileWriter
 *      √ 3.字符缓冲区流 BufferedReader & BufferedWriter
 */
public class Demo27BufferedCopyJava {
    public static void main(String[] args) throws IOException {
        long start3 = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            method3("StringDemo.java","Copy.java");
        }
        long end3 = System.currentTimeMillis();
        System.out.println("method3共耗时" + (end3 - start3) + "毫秒");//method3共耗时2840毫秒
    }

    /**
     * @introduction BufferedReader & BufferedWriter
     * 需求 : 把项目目录下的 StringDemo.java内容复制到项目目录下的Copy.java中
     * 数据源 : StringDemo.java---读数据---字符流---InputStreamReader---FileReader---BufferedReader
     * 目的地 : Copy.java---写数据---字符流---OutputStreamWriter---FileWriter---BufferedWriter
     *
     * @param source 数据源
     * @param target 目标数据
     * @throws IOException
     */
    public static void method3(String source,String target) throws IOException {
        //封装数据源
        BufferedReader br = new BufferedReader(new FileReader(source));
        //封装目的地
        BufferedWriter bw = new BufferedWriter(new FileWriter(target));
        //读写数据
        String line;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        //释放资源
        bw.close();
    }
}

3.5.4 字符缓冲区流的特殊功能

  • BufferedWriter

    //写入一个行分隔符,这个行分隔符是由系统决定的
    void newLine()
    
  • BufferedReader

    //包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
    String readLine()
    

案例代码二十八字符缓冲区流 特殊功能

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/05/08
 * @introduction 字符缓冲区流 特殊功能
 *
 * BufferedWriter
 * 		a. void newLine():写入一个行分隔符,这个行分隔符是由系统决定的
 *
 * BufferedReader
 * 		b. String readLine():包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
 */
public class Demo28BufferedMethod {
    public static void main(String[] args) throws IOException {
        //创建字符缓冲输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
        //写数据
        for (int x = 0; x < 3; x++) {
            bw.write("hello");
            //a. void newLine():写入一个行分隔符,这个行分隔符是由系统决定的
            bw.newLine();//等价于 <=> bw.write("\r\n");
            bw.flush();
        }

        //释放资源
        bw.close();

        //创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("bw.txt"));

        //创建line对象接收每一行数据
        String line;
        //b. String readLine():包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
        while ((line = br.readLine()) != null) {
            /*
                hello
                hello
                hello
             */
            System.out.println(line);
        }
        //释放资源
        br.close();
    }
}

4 NIO(new IO)


  • nio包在JDK4出现,提供了IO流的操作效率,但是目前还不是大范围的使用
  • JDK4新IO要了解的类
    • 1.Buffer(缓冲)
    • 2.Channer(通道)
  • JDK7新IO要了解的类:
    • 3.Path:与平台无关的路径
    • 4.Paths:包含了返回Path的静态方法
     //4.1 根据给定的URI来确定文件路径
     public static Path get(URI uri)
    
    • 5.Files:操作文件的工具类。提供了大量方法,简单了解如下方法
     //5.1 复制文件
     public static long copy(Path source,OutputStream out)
     //5.2 把集合的数据写到文件
     public static Path write(Path path,Iterable<? extends CharSequence> lines,
      Charset cs, OpenOption... options)
    

案例代码二十九nio(new IO)简化代码

package com.groupies.base.day13;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;

/**
 * @author GroupiesM
 * @date 2021/06/15
 * @introduction nio(new IO)简化代码
 */
public class Demo29NIO {
    public static void main(String[] args) throws IOException {
        //5.1 复制文件
        Files.copy(Paths.get("a.txt"), new FileOutputStream("copyA.txt"));

        ArrayList<String> array = new ArrayList<>();
        array.add("hello");
        array.add("world");
        array.add("java");
        //5.2 把集合的数据写到文件
        Files.write(Paths.get("array.txt"), array, Charset.forName("UTF-8"));
    }
}

5 IO流练习


5.1 练习1 键盘写入文件


  • 需求
    • 请用户从控制台输入信息,程序将信息存储到文件Info.txt中。可以输入多条信息,每条信息存储一行。当用户输入:”886”时,程序结束。

练习1Scanner通过Buffer写入文件

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/04/25
 * @introduction 课后基础练习1 Scanner通过Buffer写入文件
 *
 * 需求:请用户从控制台输入信息,程序将信息存储到文件Info.txt中。
 * 		可以输入多条信息,每条信息存储一行。当用户输入:”886”时,程序结束。
 *
 *    	123456
 *    	abcdef
 *    	886
 */
public class HomeWork1Buffer {
    public static void main(String[] args) throws IOException {
        //1.指定输出流,对应的文件Info.txt
        BufferedWriter bw = new BufferedWriter(new FileWriter("Info.txt"));
        //2.采用循环的方式,把每条信息存储到一行的Info.txt中
        Scanner sc = new Scanner(System.in);
        while (true){
            //获取键盘输入的一行内容
            System.out.println("请输入内容:");
            String next = sc.next();
            //当用户输入886时,程序结束
            if(next.equals("886")) break;
            //把内容写入到Info.txt中
            bw.write(next);//写入字符串
            bw.newLine();//写入一个行分隔符
            //bw.flush();//刷新该流的缓冲(可以省略,最后close的时候会自带一次flush)
        }
        bw.close();
    }
}

5.2 练习2 学生信息写入文件


  • 需求
    • 从控制台接收3名学员的信息,每条进行存储到一个Student对象中,
    • 将多个Student对象存储到一个集合中。输入完毕后,将所有学员信息存储到文件Student.txt中。
    • 每名学员信息存储一行,多个属性值中间用逗号隔开。

练习2Scanner接收学生信息写入文件 【a.实体学生类】

package com.groupies.base.day13;

/**
 * @author GroupiesM
 * @date 2021/04/25
 * @introduction
 */
public class HomeWork2POJOStudent {
    private String id;
    private String name;
    private String gender;
    private int age;

    public HomeWork2POJOStudent(String id, String name, String gender, int age) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

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

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

练习2Scanner接收学生信息写入文件 【b.测试类】

package com.groupies.base.day13;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * @author GroupiesM
 * @date 2021/04/25
 * @introduction 测试类 课后基础练习2 Scanner接收学生信息写入文件
 *
 * 需求:
 *      从控制台接收3名学员的信息,每条进行存储到一个Student对象中,
 * 		将多个Student对象存储到一个集合中。输入完毕后,将所有学员信息存储到文件Student.txt中。
 * 		每名学员信息存储一行,多个属性值中间用逗号隔开。
 * 分析:
 *  	1.	创建Student类,有如下属性:
 *  			学号、姓名、性别、年龄
 *  			全部属性使用String类型。要求有无参,全参构造方法。所有属性私有,并提供公有get/set方法。
 *  	2.	创建MainApp类,包含main()方法
 *  	3.	在main()方法中:
 *  		1)	定义一个存储Student对象的集合;
 *  		2)	循环3次,从控制台接收3名学员信息,每条信息封装一个Student对象,将每个Student对象存储到集合中。
 *  		3)	遍历集合,获取每个Student对象,取出所有属性值,输出到文件Test2_2.txt中。每名学员信息占一行。
 */
public class HomeWork2Buffer {
    public static void main(String[] args) throws IOException {
        //PrintWriter pw = new PrintWriter(new );

        Scanner sc = new Scanner(System.in);
        ArrayList<String[]> list = new ArrayList<>();
        int forCount = 0;//用于循环计数

        for (int i = 1; i < 4; i++) {
            System.out.println("请输入第" + i + "学生信息,用逗号分隔(学号,姓名,性别,年龄)");
            String strStudent = sc.next();
            int commaCount = 0;//逗号计数
            //校验1:判断字符串是否包含三个逗号
            String temp = strStudent;
            while (temp.contains(",")) {
                temp = temp.substring(temp.indexOf(",") + 1);
                commaCount++;
            }
            //如果不是三个逗号则重新输入
            if (commaCount != 3) {
                System.out.println("输入信息有误,请重新输入");
                i--;
                continue;
            }
            //校验2:判断输入的年龄是否为合法数字
            String[] splitStudent = strStudent.split(",");
            try {
                Integer.parseInt(splitStudent[3]);
            } catch (NumberFormatException e) {
                System.out.println("输入年龄有误,请输入正确数字");
                i--;
                continue;
            }
            //将学生信息暂时放入数组缓存
            list.add(splitStudent);
        }
        //创建字符流目标对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("student.txt"));
        //遍历list数组中的学生信息
        for (String[] sInfo : list) {
            bw.write(new HomeWork2POJOStudent(sInfo[0], sInfo[1], sInfo[2], Integer.parseInt(sInfo[3])).toString());//写入字符串
            bw.newLine();//写入一个行分隔符
            bw.flush();//刷新该流的缓冲
        }
        //释放资源
        bw.close();
    }
}

5.3 练习3 读取文件修改指定内容


  • 需求
    • 将文件name.txt中的数据“卢俊义”修改为:“史文恭”。
    • 在项目目录下创建文件name.txt,并写入以下内容:
      it001,武松,,22
      it002,林冲,,20
      it003,卢俊义,,18
      it004,石宝,,23
      

练习3Buffer读取文件后修改指定内容并写入

package com.groupies.base.day13;

import java.io.*;
import java.util.ArrayList;

/**
 * @author GroupiesM
 * @date 2021/04/25
 * @introduction 课后基础练习3 Buffer读取文件后修改指定内容并写入
 *
 * 需求:
 *      将文件name.txt中的数据“卢俊义”修改为:“史文恭”。
 *   		在项目目录下创建文件name.txt,并写入以下内容:
 * 		it001,武松,男,22
 * 		it002,林冲,男,20
 * 		it003,卢俊义,男,18
 * 		it004,石宝,男,23
 */
public class HomeWork3Buffer {
    public static void main(String[] args) throws IOException {
        //指定输入流
        BufferedReader br = new BufferedReader(new FileReader("name.txt"));
        //定义一个数组接收学生信息
        ArrayList<String[]> arrayList = new ArrayList<String[]>();
        //每次读取内容
        String line;
        String[] strArr;
        boolean b = false;
        System.out.println("开始读取文件.....");
        while ((line = br.readLine()) != null) {
            strArr = line.split(",");
            if (strArr[1].equals("卢俊义")) {
                System.out.println("检测到【卢俊义】,已修改为【史文恭】");
                strArr[1] = "史文恭";
                b = true;
            }
            arrayList.add(strArr);
        }
        if (!b) System.out.println("未检测到【卢俊义】,无需修改文件");
        if (b) {
            System.out.println("开始重新写入文件....");
            BufferedWriter bw = new BufferedWriter(new FileWriter("name.txt"));
            for (String[] sInfo : arrayList) {
                bw.write(sInfo[0] + "," + sInfo[1] + "," + sInfo[2] + "," + sInfo[3]);//写入字符串
                bw.newLine();//写入一个行分隔符
                bw.flush();//刷新该流的缓冲
            }
            //释放资源
            bw.close();

            try {
                //尝试对此部分代码捕获异常
            } catch (Exception e) {
                //捕获异常后的处理逻辑
                //e.printStackTrace(); //默认处理方式打印异常信息
            } finally {
                //无论是否捕获异常,都会执行
            }
        }
    }
}

5.4 练习4 读取文件反转行


  • 需求
    • 项目根路径下有test.txt文件,内容如下:
      我爱黑马
      123456
      
    • 利用IO流的知识读取text.txt文件的内容反转后写入test.txt文件中,内容如下:
      123456
      我爱黑马
      

练习4读取文件反转行

package com.groupies.base.day13;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;

/**
 * @author GroupiesM
 * @date 2021/04/25
 * @introduction 数组逆序
 *
 * 需求:
 *      项目根路径下有test.txt文件,内容如下:
 *      我爱黑马
 * 		123456
 * 	利用IO流的知识读取text.txt文件的内容反转后写入test.txt文件中,内容如下:
 * 		123456
 * 		我爱黑马
 *
 * 思路:
 * 		创建集合,读取内容放入集合
 * 		反转集合
 * 		把集合内容写入源文件
 * 方法:
 *      BufferedWriter.write(String); 写入字符串的某一部分。
 *      BufferedWriter.newLine(); 写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 ('\n') 符。
 *      BufferedWriter.flush(); 刷新该流的缓冲,也就是会把数据写入到目的文件里。如果没有在里面的for()循环中添加 bw.flush(); 这句话,
 *                            在循环的时候重新 new BufferedWriter();就把原来bw(缓冲区)中的覆盖掉了。于是就不能写进文件字符。
 *      BufferedWriter.close(); 关闭此流,关闭流前或默认先调用flush先刷新它。在关闭该流之后,再调用 write() 或 flush() 将导致抛出 IOException。关闭以前关闭的流无效。
 */
public class HomeWork4Buffer {
    public static void main(String[] args) throws IOException {
        //封装数据源
        BufferedReader br = new BufferedReader(new FileReader("d:" + File.separator + "test.txt"));
        //定义字符数组,存放读取到的数据
        ArrayList<String> list = new ArrayList<String>();
        //每次读取到的数据
        String line;

        while ((line = br.readLine()) != null) {
            list.add(line);
        }

        //反转集合
        //方式1:逆向遍历集合 list.fori
/*        for (int i = 0; i < list.size() / 2; i++) {
            //第一个和最后一个交换,第二个和倒数第二个交换..
            String first = list.get(i);
            String last = list.get(list.size() - i - 1);
            list.set(i, last);//第i个值
            list.set(list.size() - i - 1, last);
        }*/

        //方式2:Collections.revers
        Collections.reverse(list);

        //封装目标
        BufferedWriter bw = new BufferedWriter(new FileWriter("d:" + File.separator + "test.txt"));
        //写入数据
        for (int i = 0; i < list.size(); i++) {
            //写入字符串
            //bw.write(list.get(i), 0, list.get(i).length());
            bw.write(list.get(i));
            //写入一个行分隔符
            bw.newLine();
            bw.flush();//将缓冲区内容 写入目标文件
        }

        //释放资源
        br.close();
        bw.close();
    }
}

5.5 练习5 字符流五种方式读写


  • 需求
    • 复制文件到指定目录(字符流五种方式)
    • 数据源:
      • d:\林青霞.txt
    • 目标:
      • 窗里窗外.txt

  • 字符流五种方式

    • 基本字符流 FileReader

      • 基本字符流一次读写一个字符

        //method1
        int ch;
        while ((ch = fr.read()) != -1) {
            fw.write(ch);
        }
        
      • 基本字符流一次读写一个字符数组

        //method2
        char[] chs = new char[1024];
        int len;
        while((len=fr.read(chs))!=-1) {
            fw.write(chs, 0, len);
        }
        
    • 缓冲字符流 BufferedReader

      • 缓冲字符流一次读写一个字符

        //method3
        int ch;
        while((ch=br.read())!=-1) {
            bw.write(ch);
        }
        
      • 缓冲字符流一次读写一个字符数组

        //method4
        char[] chs = new char[1024];
        int len;
        while((len=br.read(chs))!=-1) {
            bw.write(chs, 0, len);
        }
        
      • 缓冲字符串一次读写一行

        //method5
        String line;
        while((line=br.readLine())!=null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        

  • 注意
    • 因为这五种方法读取数据时不能指定编码,所以写入数据时一定要注意读写编码一致(默认编码 JDK7 GBK / JDK8 UTF-8)

练习5字符流复制文本文件的五种方式

package com.groupies.base.day13;

import java.io.*;

/**
 * @author GroupiesM
 * @date 2021/05/10
 * @introduction 字符流复制文本文件的五种方式
 *
 * 需求:
 *      复制文件到指定目录(字符流五种方式)
 * 数据源:
 *      d:\\林青霞.txt
 * 目标:
 *      窗里窗外.txt
 *
 *
 * 五种方式:
 * 	    基本字符流一次读写一个字符
 *      基本字符流一次读写一个字符数组
 *      缓冲字符流一次读写一个字符
 *      缓冲字符流一次读写一个字符数组
 *      缓冲字符串一次读写一行
 *
 * 注意:
 *      因为这五种方法读取数据时不能指定编码,所以写入数据时一定要注意读写编码一致(默认编码 JDK7 GBK / JDK8 UTF-8)
 */
public class HomeWork5CopyTxt {
    public static void main(String[] args) throws IOException {
        /*
            创建数据源 d:\\林青霞.txt
            使用java8环境(默认读写字符集为UTF-8)
            因为这五种方法读取数据时不能指定编码,所以写入数据时一定要注意读写编码一致(默认编码 JDK7 GBK / JDK8 UTF-8)
        */
        createFile();

        //基本字符流一次读写一个字符
        Long start1 = System.currentTimeMillis();
        method1("d:" + File.separator + "林青霞.txt", "窗里窗外1.txt");
        Long end1 = System.currentTimeMillis();
        System.out.println("method1共耗时:" + (end1 - start1) + "毫秒");//method1共耗时:436毫秒

        //基本字符流一次读写一个字符数组
        Long start2 = System.currentTimeMillis();
        method2("d:" + File.separator + "林青霞.txt", "窗里窗外2.txt");//method2共耗时:43毫秒
        Long end2 = System.currentTimeMillis();
        System.out.println("method2共耗时:" + (end2 - start2) + "毫秒");

        //缓冲字符流一次读写一个字符
        Long start3 = System.currentTimeMillis();
        method3("d:" + File.separator + "林青霞.txt", "窗里窗外3.txt");//method3共耗时:22毫秒
        Long end3 = System.currentTimeMillis();
        System.out.println("method3共耗时:" + (end3 - start3) + "毫秒");

        //缓冲字符流一次读写一个字符数组
        Long start4 = System.currentTimeMillis();
        method4("d:" + File.separator + "林青霞.txt", "窗里窗外4.txt");//method4共耗时:22毫秒
        Long end4 = System.currentTimeMillis();
        System.out.println("method4共耗时:" + (end4 - start4) + "毫秒");

        //缓冲字符串一次读写一行
        Long start5 = System.currentTimeMillis();
        method5("d:" + File.separator + "林青霞.txt", "窗里窗外5.txt");//method5共耗时:22毫秒
        Long end5 = System.currentTimeMillis();
        System.out.println("method5共耗时:" + (end5 - start5) + "毫秒");
    }

    /**
     * @introduction 创建数据源 d:\\林青霞.txt 供下一步读取使用
     * @throws IOException
     */
    public static void createFile() throws IOException {
        //指定输出流 目标文件和字符集
        OutputStreamWriter oswGBKSource = new OutputStreamWriter(new FileOutputStream("d:\\林青霞.txt"), "UTF-8");
        oswGBKSource.write("林青霞1\r\n");
        oswGBKSource.write("林青霞2\r\n");
        oswGBKSource.write("林青霞3\r\n");
        oswGBKSource.close();
    }

    /**
     * @introduction 基本字符流一次读写一个字符
     * @param source 数据源
     * @param target 目标文件
     * @throws IOException
     */
    private static void method1(String source, String target) throws IOException {
        FileReader fr = new FileReader(source);
        FileWriter fw = new FileWriter(target);

        int ch;
        while ((ch = fr.read()) != -1) {
            fw.write(ch);
        }
        fw.close();
        fr.close();
    }

    /**
     * @introduction 基本字符流一次读写一个字符数组
     * @param source 数据源
     * @param target 目标文件
     * @throws IOException
     */
    private static void method2(String source, String target) throws IOException {
        FileReader fr = new FileReader(source);
        FileWriter fw = new FileWriter(target);

        char[] chs = new char[1024];
        int len;
        while ((len = fr.read(chs)) != -1) {
            fw.write(chs, 0, len);
        }
        fw.close();
        fr.close();
    }

    /**
     * @introduction 缓冲字符流一次读写一个字符
     * @param source 数据源
     * @param target 目标文件
     * @throws IOException
     */
    private static void method3(String source, String target) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(source));
        BufferedWriter bw = new BufferedWriter(new FileWriter(target));

        int ch;
        while ((ch = br.read()) != -1) {
            bw.write(ch);
        }
        bw.close();
        br.close();
    }

    /**
     * @introduction 缓冲字符流一次读写一个字符数组
     * @param source 数据源
     * @param target 目标文件
     * @throws IOException
     */
    private static void method4(String source, String target) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(source));
        BufferedWriter bw = new BufferedWriter(new FileWriter(target));

        char[] chs = new char[1024];
        int len;
        while ((len = br.read(chs)) != -1) {
            bw.write(chs, 0, len);
        }
        bw.close();
        br.close();
    }

    /**
     * @introduction 缓冲字符流一次读写一个字符串
     * @param source 数据源
     * @param target 目标文件
     * @throws IOException
     */

    private static void method5(String source, String target) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(source));
        BufferedWriter bw = new BufferedWriter(new FileWriter(target));

        String line;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        bw.close();
        br.close();
    }
}

5.6 练习6 ArrayList到TXT


  • 需求
    • A:创建集合对象
    • B:往集合中添加字符串元素
    • C:创建字符缓冲输出流对象
    • D:遍历集合,得到每一个字符串元素,把字符串元素作为数据写入到文本文件
    • E:释放资源

练习6字符流-ArrayList到TXT

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/05/10
 * @introduction 字符流-ArrayList到TXT
 *
 * 需求:
 *      A:创建集合对象
 * 	    B:往集合中添加字符串元素
 * 	    C:创建字符缓冲输出流对象
 * 	    D:遍历集合,得到每一个字符串元素,把字符串元素作为数据写入到文本文件
 * 	    E:释放资源
 */
public class HomeWork6ArrayListToTxt {
    public static void main(String[] args) throws IOException {
        //创建集合对象
        ArrayList<String> array = new ArrayList<>();

        //往集合中添加字符串元素
        array.add("hello");
        array.add("world");
        array.add("java");

        //创建字符缓冲输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("array.txt"));

        //遍历集合,得到每一个字符串元素,把字符串元素作为数据写入到文本文件
        for (String s : array) {
            bw.write(s);
            bw.newLine();
            bw.flush();
        }

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

5.7 练习7 TXT到ArrayList


  • 需求
    • 从文本文件中读取数据到ArrayList集合中,并遍历集合
    • 每一行数据作为一个字符串元素

  • 数据源
    • 练习6中生成的文件student.txt

  • 分析
    • A:创建字符缓冲输入流对象
    • B:创建集合对象
    • C:读取数据,每一次读取一行,并把该数据作为元素存储到集合中
    • D:释放资源
    • E:遍历集合

练习7字符流-TXT到ArrayList

package com.groupies.base.day13;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

/**
 * @author GroupiesM
 * @date 2021/05/10
 * @introduction
 *
 *  需求:
 *      从文本文件中读取数据到ArrayList集合中,并遍历集合
 *  	每一行数据作为一个字符串元素
 *
 * 	分析:
 * 		A:创建字符缓冲输入流对象
 *  	B:创建集合对象
 * 		C:读取数据,每一次读取一行,并把该数据作为元素存储到集合中
 * 		D:释放资源
 * 		E:遍历集合
 */
public class HomeWork7TxtToArrayList {
    //指定数据源
    final static String sourceFile = "array.txt";
    
    public static void main(String[] args) throws IOException {
        //创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader(sourceFile));

        //创建集合对象
        ArrayList<String> array = new ArrayList<>();

        //读取数据,每次读取一行,并把改数据作为元素存储到集合中
        String line;
        while ((line = br.readLine()) != null) {
            array.add(line);
        }

        //释放资源
        br.close();

        //遍历集合
        for (String s : array) {
            System.out.println(s);
        }
    }
}

5.8 练习8 Array到TXT


  • 需求

    • 把ArrayList集合中的学生数据存储到文本文件
    • 每一个学生数据作为文件中的一行数据
  • 定义一个学生类

    • 学生:
      • 学号,姓名,年龄,所在城市
        it001,张曼玉,35,北京
        it002,王祖贤,33,上海
        it003,林青霞,30,西安
        

  • 分析
    • A:创建集合对象
    • B:创建学生对象
    • C:把学生对象添加到集合中
    • D:创建字符缓冲输出流对象
    • E:遍历集合,得到每一个学生对象,然后把该对象的数据拼接成一个指定格式的字符串写到文本文件
    • F:释放资源

练习8Array到TXT 【a.学生类】

package com.groupies.base.day13;

/**
 * @author GroupiesM
 * @date 2021/05/10
 * @introduction
 */
public class HomeWork8POJOStudent {
    private String id;
    private String name;
    private int age;
    private String location;

    public HomeWork8POJOStudent() {
    }

    public HomeWork8POJOStudent(String id, String name, int age, String location) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.location = location;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    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 String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    /**
     * @introduction 逗号分隔学生信息
     * @return
     */
    @Override
    public String toString() {
        return id + "," + name + "," + age + "," + location;
    }
}

练习8Array到TXT 【b.测试类】

package com.groupies.base.day13;

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

/**
 * @author GroupiesM
 * @date 2021/05/10
 * @introduction
 */
public class HomeWork8ArrayListToTxt {
    //写入目标文件
    final static String targetFile = "student.txt";

    public static void main(String[] args) throws IOException {
        //创建集合对象
        ArrayList<HomeWork8POJOStudent> array = new ArrayList<>();

        //创建学生对象
        HomeWork8POJOStudent s1 = new HomeWork8POJOStudent("it001", "张曼玉", 35, "北京");
        HomeWork8POJOStudent s2 = new HomeWork8POJOStudent("it002", "王祖贤", 33, "上海");
        HomeWork8POJOStudent s3 = new HomeWork8POJOStudent("it003", "林青霞", 30, "西安");

        // 把学生对象添加到集合中
        array.add(s1);
        array.add(s2);
        array.add(s3);

        //创建字符缓冲流输出对象
        BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile));

        //拼接学生信息到字符串中
        StringBuilder sb = new StringBuilder();

        //遍历集合,得到每一个学生对象,然后把该对象的数据接成一个指定格式的字符串写到文本文件
        for (HomeWork8POJOStudent s : array) {
            sb.append(s.toString());
            sb.append("\r\n");
        }

        /*
            正在将以下信息写入目标文件=>student.txt
            it001,张曼玉,35,北京
            it002,王祖贤,33,上海
            it003,林青霞,30,西安
         */
        System.out.println("正在将以下信息写入目标文件=>" + targetFile);
        System.out.println(sb);

        bw.write(sb.toString());
        //刷新缓存并释放资源 flush
        bw.close();
    }
}

5.9 练习9 TXT到Array


  • 需求
    • 从文本文件中读取学生数据到ArrayList集合中,并遍历集合
    • 每一行数据作为一个学生元素
      it001,张曼玉,35,北京
      it002,王祖贤,33,上海
      it003,林青霞,30,西安
      
    • 这里我们要使用String类中的一个方法:split()

  • 数据源
    • 练习8中生成的文件student.txt

  • 分析
    • A:创建字符缓冲输入流对象
    • B:创建集合对象
    • C:读取数据,每一次读取一行数据,把该行数据想办法封装成学生对象,并把学生对象存储到集合中
    • D:释放资源
    • E:遍历集合

练习9Array到TXT 【a.学生类】

package com.groupies.base.day13;

/**
 * @author GroupiesM
 * @date 2021/05/10
 * @introduction
 */
public class HomeWork9POJOStudent {
    private String id;
    private String name;
    private int age;
    private String location;

    public HomeWork9POJOStudent() {
    }

    public HomeWork9POJOStudent(String id, String name, int age, String location) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.location = location;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    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 String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

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

练习9Array到TXT 【b.测试类】

package com.groupies.base.day13;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

/**
 * @author GroupiesM
 * @date 2021/05/10
 * @introduction
 */
public class HomeWork9TxtToArrayList {
    //指定数据源
    final static String sourceFile = "student.txt";

    public static void main(String[] args) throws IOException {
        //创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader(sourceFile));

        //创建集合对象
        ArrayList<HomeWork9POJOStudent> array = new ArrayList<>();

        //读取数据,每次读取一行数据,把该行业数据想办法封装成学生对象,并把学生对象存储到集合中
        String line;

        HomeWork9POJOStudent student;
        while ((line = br.readLine()) != null) {
            //按逗号分隔字符串对象,存入字符数组
            String[] strArray = line.split(",");

            student = new HomeWork9POJOStudent();
            student.setId(strArray[0]);
            student.setName(strArray[1]);
            student.setAge(Integer.parseInt(strArray[2]));
            student.setLocation(strArray[3]);

            array.add(student);
        }

        // 释放资源
        br.close();
        
        // 遍历集合
        for (HomeWork9POJOStudent s : array) {
            /*
                {id='it001', name='张曼玉', age=35, location='北京'}
                {id='it002', name='王祖贤', age=33, location='上海'}
                {id='it003', name='林青霞', age=30, location='西安'}
             */
            System.out.println(s.toString());
        }
    }
}

21/05/10

M

你可能感兴趣的:(三.Java,java)