文件读写,字节输入流,字节输出流

- File对象的创建方式
	public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。  
	public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。
	public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。  
- File类常用方法
	public String getName()  :获取构造方法中路径的名称(末尾部分)
	String getAbsolutePath() : 获取构造方法中路径的绝对路径
	public long length()  :获取文件的大小,单位是字节
	public boolean isDirectory() :是否为目录(文件夹)public boolean exists() :判断构造方法中传递的路径是否存在
	public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
	public boolean mkdir() :创建单级文件夹
	public boolean mkdirs() :即可以创建单级文件夹,又可以创建多级文件夹
	public boolean delete() :删除文件和文件夹,不走回收站
- 辨别相对路径和绝对路径
	绝对:以盘符开始
	相对:相对当前项目的根目录而言;使用项目的跟目录可以省略书写(不是盘符开始)
	绝对:D:\\Work_idea\\aa\\bb\\a.txt
	相对:bb\\a.txt
- 遍历文件夹
	public String[] list() :
        遍历构造方法传递的文件夹,获取文件夹中每一个文件|子文件夹的名称,把多个名称存储到一个String类型的数组中返回
    public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
        遍历构造方法传递的文件夹,获取文件夹中每一个文件|子文件夹,把文件|子文件夹封装为File对象,多个File对象存储到一个File类型的数组中返回
- 递归的含义
	方法自己调用自己
- 递归计算5的阶乘
	public static int jc(int n) {//方法的主体不变,每次调用自己参数在发生变化5,4,3,2,1
		//递归结束的条件:获取到1的时候结束
		if(n==1){
			return 1;
		}
		//递归的目的:获取下一个被乘的数字n-1
		return n * jc(n-1);
	}
- 使用递归会内存溢出隐患的原因
	方法自己调用自己,没有结束条件,栈内存中会有无数多个方法,如果方法过多超出了栈内存是范围就会发生内存溢出
- IO流的分类和功能
	输入流:把硬盘上的数据读取到内存中
		字符输入流:读取字符
		字节输入流:读取字节
	输出流:把内存中的数据写入到硬盘中
		字符输出流:写入字符
		字节输出流:写入字节
- 字节输出流写出数据到文件
	1.创建FileOutputStream对象,构造方法中传递写入数据的目的地
  	2.调用FileOutputStream对象中的方法write,把数据写入到文件中
  	3.释放资源
- 字节输入流读取数据到程序
	1.创建FileInputStream字节输入流对象,构造方法中绑定要读取的数据源
	2.使用FileInputStream对象中的方法read,读取文件
	3.释放资源
- 读取数据read(byte[])方法的原理
	1.字节数组的作用?
		起到缓冲作用,可以把多次读取到的字节,缓冲到数组中,一次性返回效率高
		数组的长度一把定义为1024或者1024的整数倍
	2.read方法的返回值int是什么?
		每次读取的有效字节个数
- 字节流完成文件的复制
	1.创建字节输入流对象构造方法中绑定要读取的数据源
	2.创建字节输出流对象构造方法中绑定要写入的目的地
	3.使用字节输入流中的方法read,读取文件
	4.使用字节输出流中的方法write,把读取到字节,写入到文件中
	5.释放资源
- FileWriter写数据的5个方法
	void write(String str):写一个字符串数据
	void write(String str,int index,int len):写一个字符串中的一部分数据, index:开始索引,len:写几个
	void write(int ch):写一个字符数据,这里写int类型的好处是既可以写char类型的数据,也可以写char对应的int类型的值。'a',97
	void write(char[] chs):写一个字符数组数据
	void write(char[] chs,int index,int len):写一个字符数组的一部分数据, index:开始索引,len:写几个
- FileWriter中关闭和刷新方法的区别
	flush方法:把内存缓冲区中的数据,刷新到文件中,流对象可以继续使用
	close方法:先调用flush方法,把内存缓冲区中的数据,刷新到文件中;		
			  然后在释放和操作系统有关的资源,并关闭流,流就不能在继续使用了
- FileWriter写数据实现换行和追加写
	FileWriter追加写使用两个参数的构造方法
		FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。
			参数:
				String fileName:要写入数据的文件路径
				boolean append:追加写的开关,true:可以追加写;false:不能追加写(会覆盖)
	FileWriter写数据时换行问题
		可以使用换行符号
		windows:\r\n
		linux:/n
		mac:/r
- FileReader读数据一次一个字符
	//1.创建字符输入流FileReader对象,并且绑定要读取数据的数据源
		FileReader fr = new FileReader("bb\\d.txt");
	//2.使用FileReader中读取数据的read方法,读取文件中的数据
		int len = 0;//记录每次读取字符
		while((len = fr.read())!=-1){
			System.out.print((char)len);
		}
	//3.释放资源
		fr.close();
- FileReader读数据一次一个字符数组
	//1.创建字符输入流FileReader对象,并且绑定要读取数据的数据源
		FileReader fr = new FileReader("d.txt");
	//2.使用FileReader中读取数据的read方法,读取文件中的数据
		char[] arr = new char[1024*10];
		int len = 0; //记录每次读取的有效字符个数
		while((len = fr.read(arr))!=-1){
			System.out.println(new String(arr,0,len));
		}
	//3.释放资源
		fr.close();

一 File类

1.File类介绍

/*
    java.io.File类
        文件和目录路径名的抽象表示形式。
        File类封装了计算机中的文件和文件夹,我们可以使用File类中的方法操作计算机中的文件和文件夹
        可以使用File中的方法创建文件|文件夹
        可以使用File中的方法删除文件|文件夹
        可以使用File中的方法获取文件|文件夹的路径
        可以使用File中的方法遍历文件夹
        可以使用File中的方法获取文件的大小
   必须的记住的三个单词
        file:文件
        directory:目录,文件夹
        path:路径
    File类是一个与系统无关的类,任何的操作系统都可以使用File的功能
 */

2.File类的静态成员变量

public class Demo01File {
    public static void main(String[] args) {
        /*
            File类的静态成员变量
            static String pathSeparator 与系统有关的路径分隔符,为了方便,它被表示为一个字符串。
            static char pathSeparatorChar 与系统有关的路径分隔符。
            static String separator 与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。
            static char separatorChar 与系统有关的默认名称分隔符。
         */
        String pathSeparator = File.pathSeparator;
        System.out.println(pathSeparator);//路径分隔符  windows:分号(;)  linux:冒号(:)

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

        String path = "d:\\a.txt";
        path = "d:"+File.separator+"a.txt";
        System.out.println(path);
    }
}

3.路径

/*
    路径
        绝对路径:以盘符开始的路径
            c:\\a.txt
            d:\\afadsfad\\aaa\\bbb\\bbbb
        相对路径:相当于当前项目的根目录而言,我们使用项目的根目录作为路径,可以省略书写
    注意:
        路径是不区分大小写的
        在java程序中,也可以使用一个正斜杠(/)作为文件名称分隔符
        如果要使用反斜杠(\),需要写2个,本身是转义字符
 */

4.File类的构造方法(必须会)

public class Demo02File {
    public static void main(String[] args) {
        show02("d:","a.txt");//d:\a.txt
        show02("c:","a.txt");//c:\a.txt
        show03();
    }

    /*
        File类的构造方法:
        File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
        构造方法把路径分割为了两部分
            File parent:父路径
            String child:子路径
        好处:
            父路径和子路径可以分别使用不同的路径,变化更加灵活
            父路径是File类型,可以先使用File类中的方法对父路径进行一些操作,在和子路径组成一个File对象
     */
    private static void show03() {
        File parent = new File("d:");
        File f = new File(parent,"a.txt");
        System.out.println(f);//d:\a.txt
    }

    /*
        File类的构造方法:
        File(String parent, String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
        构造方法把路径分割为了两部分
            String parent:父路径
            String child:子路径
        好处:
            父路径和子路径可以分别使用不同的路径,变化更加灵活
     */
    private static void show02(String parent, String child) {
        File file = new File(parent,child);
        System.out.println(file);
    }

    /*
        File类的构造方法:
        File(String pathname)通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
        参数:
            String pathname:创建路径的名称
        注意:
            传递的路径可以是绝对路径,也可以是相对路径
            传递的路径可以是以文件结尾的,也可以是以文件夹结尾
            传递的路径可以是存在的,也可以是不存在的;构造方法仅仅是把字符串的路径,转换为File对象,不考虑路径的真假
     */
    private static void show01() {
        File f1 = new File("c:\\a.txt");
        System.out.println(f1);//c:\a.txt

        File f2 = new File("c:\\abc\\aaa\\bbb");
        System.out.println(f2);//c:\abc\aaa\bbb

        File f3 = new File("bb");
        System.out.println(f3);
    }
}

5.File类的成员方法_获取功能的方法

import java.io.File;

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

    /*
        - public long length()  :获取文件的大小,单位是字节
        注意:
            length方法只能获取文件的大小,不能获取文件夹的大小
            length方法获取文件如果不存在,那么返回0
     */
    private static void show04() {
        File f1 = new File("D:\\base\\20201220\\cs\\测试.java");
        long l1 = f1.length();
        System.out.println(l1);//6195 字节

        File f2 = new File("c:\\afadsfafadsf.txt");
        System.out.println(f2.length());//0

        File f3 = new File("D:\\base\\20201220\\cs\\avi");
        System.out.println(f3.length());//0

        File f4 = new File("D:\\base\\20201220");
        System.out.println(f4.length());//4096
    }

    /*
        - public String getName()  :获取构造方法中路径末尾的文件|文件夹的名称
     */
    private static void show03() {
        File f1 = new File("c:\\abc\\aaa\\a.txt");
        System.out.println(f1.getName());// a.txt

        File f2 = new File("c:\\abc\\aaa");
        System.out.println(f2.getName());//aaa

        File f3 = new File("20201220\\abc\\b.txt");
        System.out.println(f3.getName());// b.txt
    }

    /*
        - public String getPath() 获取构造方法中传递路径
        File类重写了Object类的toString方法
            public String toString() {
                return getPath();
            }
     */
    private static void show02() {
        File f1 = new File("c:\\abc\\aaa\\a.txt");
        System.out.println(f1.getPath());//c:\abc\aaa\a.txt

        File f2 = new File("20201220");
        System.out.println(f2.getPath());
        System.out.println(f2.toString());
    }

    /*
        - public String getAbsolutePath() :获取构造方法中传递的路径绝对路径
        - File getAbsoluteFile() 返回此抽象路径名的绝对路径名形式。
        注意:
            无论构造方法中传递的路径是绝对的,还是相对的,返回的都是绝对路径
            传递相对的,会在路径前边加上项目的根目录(D:\Work_idea\1220)
     */
    private static void show01() {
        File f1 = new File("c:\\abc\\aaa\\a.txt");
        String a1 = f1.getAbsolutePath();
        System.out.println(a1);//c:\abc\aaa\a.txt

        File f2 = new File("1220");
        System.out.println(f2.getAbsolutePath());// D:\Work_idea\1220\cd

        File a2 = f2.getAbsoluteFile();
        System.out.println(a2.exists());//true
    }
}

7.File类的成员方法_判断功能的方法

import java.io.File;

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

    /*
        - public boolean isDirectory() 判断构造方法中传递的路径是一个以文件夹结尾的路径吗
            是文件夹,返回true
            不是文件夹,返回false
        - public boolean isFile() 判断构造方法中传递的路径是一个以文件结尾的路径吗
            是文件,返回true
            不是文件,返回false
        注意:
            1.构造方法中的路径必须是存在的,在判断是文件还是文件夹,否则没有意义,都会返回false
            2.计算机中只有文件和文件夹,所以两个方法互斥
     */
    private static void show02() {
        File f1 = new File("c:\\a.txt");
        if(f1.exists()){
            boolean b1 = f1.isDirectory();
            System.out.println("b1:"+b1);//b1:false

            boolean b2 = f1.isFile();
            System.out.println("b2:"+b2);//b1:false
        }
        System.out.println("--------------------");
        File f2 = new File("1220");
        if(f2.exists()){
            boolean b1 = f2.isDirectory();
            System.out.println("b1:"+b1);//b1:true

            boolean b2 = f2.isFile();
            System.out.println("b2:"+b2);//b1:false
        }
        System.out.println("-------------------");
        File f3 = new File("1220\\a.txt");
        if(f3.exists()){
            boolean b1 = f3.isDirectory();
            System.out.println("b1:"+b1);//b1:false

            boolean b2 = f3.isFile();
            System.out.println("b2:"+b2);//b1:true
        }
    }

    /*
       - public boolean exists() 判断构造方法中的路径是否存在
            存在:返回true
            不存在:返回false
     */
    private static void show01() {
        File f1 = new File("c:\\a.txt");
        System.out.println(f1.exists());//false

        File f2 = new File("c:\\测试.txt");
        System.out.println(f2.exists());//true

        File f3 = new File("1220");
        System.out.println(f3.exists());//true
    }
}

8.File类的成员方法_创建删除功能的方法

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

/*
    File类的成员方法_创建删除功能的方法
        - public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
        - public boolean delete() :删除由此File表示的文件或目录。
        - public boolean mkdir() :创建由此File表示的目录。
        - public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
 */
public class Demo05Method {
    public static void main(String[] args) throws IOException {
        show03();
        
    }

    /*
        - public boolean delete() 删除构造方法中指定的文件或者文件夹
        返回值:boolean
            构造方法中路径存在,删除文件|文件夹,返回true
            构造方法中路径不存在,文件夹中有内容,不会删除,返回false
        注意:
            此删除方法不走回收站,直接在硬盘删除,需要谨慎
     */
    private static void show03() {
        File f1 = new File("1220\\a.txt");
        boolean b1 = f1.delete();
        System.out.println("b1:"+b1);

        File f2 = new File("1220\\a");
        boolean b2 = f2.delete();
        System.out.println("b2:"+b2);

        File f3 = new File("1220\\aaa");
        boolean b3 = f3.delete();
        System.out.println("b3:"+b3);
    }

    /*
        - public boolean mkdir() :只能创建单级文件夹
        - public boolean mkdirs() :既能创建单级文件夹,又能创建多级文件夹
        作用:
            用于创建一个空白的文件夹
        返回值:boolean
             文件夹不存在,创建成功返回true
             文件夹存在,不会创建,返回false;构造方法中的路径不存在,返回false
        注意:
            1.创建文件夹的路径需要在构造方法中给出
            2.此方法只能创建文件夹,不能创建文件
     */
    private static void show02() {
        File f1 = new File("1220\\a");
        boolean b1 = f1.mkdir();
        System.out.println("b1:"+b1);

        File f2 = new File("1220\\aaa\\bbb\\ccc\\ddd\\eee\\fff");
        boolean b2 = f2.mkdirs();
        System.out.println("b2:"+b2);

        File f3 = new File("w:\\aaa");
        boolean b3 = f3.mkdir();
        System.out.println("b3:"+b3);//b3:false 路径不存在
    }

    /*
        - public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
        作用:
            用于创建一个新的空白文件
        返回值:boolean
             文件不存在,创建成功返回true
             文件存在,不会创建,返回false(不会覆盖)
        注意:
            1.此方法只能创建文件,不能创建文件夹
            2.创建文件的路径和名称在构造方法中给出,必须存在,否则会抛出异常
            3.有些操作系统(win10),c盘是没有权限创建文件的,会抛出拒绝访问异常
     */
    private static void show01() throws IOException {
        File f1 = new File("d:\\aaa.txt");
        boolean b1 = f1.createNewFile();
        System.out.println("b1:"+b1);

        File f2 = new File("1220\\c.txt");
        boolean b2 = f2.createNewFile();
        System.out.println("b2:"+b2);

        File f3 = new File("1220\\新建文件夹");//创建一个文件,文件的名称叫新建文件夹
        boolean b3 = f3.createNewFile();
        System.out.println("b3:"+b3);

        //File f4 = new File("w:\\a.txt");//IOException: 系统找不到指定的路径。
        File f4 = new File("d:\\aaaaaaa\\a.txt");//IOException: 系统找不到指定的路径。
        boolean b4 = f4.createNewFile();
    }
}

9.File类的成员方法_目录的遍历的方法

import java.io.File;

/*
    File类的成员方法_目录的遍历的方法
        - public String[] list()
            遍历文件夹,获取文件夹中每一个文件|文件夹的名称,把多个名称存储到一个String类型的数组中返回
        - public File[] listFiles()
            遍历文件夹,获取文件夹中每一个文件|文件夹,把文件|文件夹封装为File对象,多个File对象存储到一个File类型的数组中返回
    注意:
        1.遍历文件夹的路径,在构造方法中给出
        2.遍历文件夹的路径必须是存在的,否则会抛出空指针异常
        3.这两个方法只能遍历文件夹,不能遍历文件;如果要遍历文件,也会抛出空指针异常
 */
public class Demo06Method {
    public static void main(String[] args) {
        show02();
    }

    /*
        - public File[] listFiles()
            遍历文件夹,获取文件夹中每一个文件|文件夹,把文件|文件夹封装为File对象,多个File对象存储到一个File类型的数组中返回
     */
    private static void show02() {
        File file = new File("D:\\base\\20201220\\cs");
        //File file = new File("D:\\base\\20201220\\cs\\a.txt");//NullPointerExceptiond
        //File file = new File("w:\\aaa");//NullPointerExceptiond
        File[] files = file.listFiles();
        for (File f : files) {
            System.out.println(f);
        }
    }

    /*
        - public String[] list()
            遍历文件夹,获取文件夹中每一个文件|文件夹的名称,把多个名称存储到一个String类型的数组中返回
     */
    private static void show01() {
        File file = new File("D:\\base\\20201220\\cs");
        String[] arr = file.list();
        for (String s : arr) {
            System.out.println(s);
        }
    }
}

二 递归

1.递归的概述

/*
    递归:方法自己调用自己
    递归的分类:
        1.直接递归
            public void a(){
                a();
            }
        2.间接递归
            public void a(){
                b();
            }
            public void b(){
                a();
            }
    递归的注意事项:
        1.递归必须有结束的条件,否则会抛出内存溢出的错误
        2.递归有结束的条件,但是递归的次数不能太多了,否则也会抛出内存溢出的错误
        3.构造方法禁止递归
    什么时候使用递归:
        当我们频繁的调用一个方法,方法的主体不变,每次调用的参数改变,就可以使用递归
 */
public class Demo01Recursion {
    public static void main(String[] args) {
        //a();
        //b(1);
    }

    /*
        3.构造方法禁止递归
        构造方法是创建对象使用的,一直对象,在内存中就会有无数多个对象
     */
    public Demo01Recursion() {
        //Demo01Recursion();
    }

    /*
            2.递归有结束的条件,但是递归的次数不能太多了,否则也会抛出内存溢出的错误
            11420
            11409
                Exception in thread "main" java.lang.StackOverflowError
         */
    private static void b(int i) {//1 2 3 4 5 ....
        System.out.println(i);
        if(i==20000){
            return;
        }
        b(++i);
    }

    /*
        1.递归必须有结束的条件,否则会抛出内存溢出的错误
        java.lang.StackOverflowError
     */
    private static void a() {
        System.out.println("a方法!");
        a();
    }
}

在这里插入图片描述

2.练习:使用递归计算1-n的和

/*
    练习:
        使用递归计算1-n的和
 */
public class Demo02Recursion {
    public static void main(String[] args) {
        int s = sum(3);
        System.out.println(s);
    }

    /*
        定义一个计算1-n和的方法
        1-n的和就是n-1的和
        n+(n-1)+(n-2)+(n-3)+...+1
        已知:
            1
            n:10,100,1000
        未知:
            n-1
        递归的目的:获取下一个被加的数字n-1
        递归的结束条件:当n-1=1的时候,结束获取
     */
    public static int sum(int n){//10,9,8,7,6,...1
        //递归的结束条件:当n-1=1的时候,结束获取
        if(n==1){
            return 1;
        }
        //递归的目的:获取下一个被加的数字n-1
        return n+sum(n-1);
    }
}

3.递归求和的原理

在这里插入图片描述

4.练习:递归求阶乘


/*
    练习:递归求阶乘
    5!=5*4*3*2*1
    n! = n * (n-1) *...* 3 * 2 * 1
 */
public class Demo03Recursion {
    public static void main(String[] args) {
        int jc = jc(5);
        System.out.println(jc);//120
    }

    /*
        n! = n * (n-1) *...* 3 * 2 * 1
        已知:
            n
            1
        未知:
            n-1
        递归的结束条件:n-1=1的时候结束
        递归的目的:获取n-1
     */
    private static int jc(int n) {//5,4,3,2,1
        //递归的结束条件:n-1=1的时候结束
        if(n==1){
            return 1;
        }
        //递归的结束条件:n-1=1的时候结束
        return n * jc(n-1);
    }
}

5.练习:使用递归遍历文件夹已经文件夹中的子文件夹

import java.io.File;

/*
    练习:使用递归遍历文件夹已经文件夹中的子文件夹
    d:\\aaa
    d:\\aaa\\aaa.java
    d:\\aaa\\aaa.txt
    d:\\aaa\\a
    d:\\aaa\\a\\a.java
    d:\\aaa\\a\\a.jpg
    d:\\aaa\\b
    d:\\aaa\\b\\B.JAVA
    d:\\aaa\\b\\b.avi
 */
public class Demo04Recursion {
    public static void main(String[] args) {
        File file = new File("d:\\aaa");
        getAllFile(file);
    }

    /*
        定义一个方法,参数传递要遍历文件夹
        方法内部对文件夹进行遍历
     */
    public static void getAllFile(File dir){
        System.out.println(dir);//打印遍历的文件夹
        File[] files = dir.listFiles();
        for (File file : files) {
            //判断遍历得到的file是否是一个文件夹
            if(file.isDirectory()){
                //file是一个文件夹,继续遍历这个文件夹
                //而我们发现getAllFile,就是一个传递文件夹,遍历文件夹的方法
                //调用getAllFile方法,传递文件夹即可
                getAllFile(file);// 方法自己调用自己==>递归
            }else{
                //file就是一个文件,打印==>toString方法
                System.out.println(file);
            }
        }
    }
}

在这里插入图片描述

6.练习:文件搜索

import java.io.File;

/*
    练习:文件搜索
        使用递归遍历文件夹已经文件夹中的子文件夹
        只打印以.java结尾的文件
    d:\\aaa
    d:\\aaa\\aaa.java
    d:\\aaa\\aaa.txt
    d:\\aaa\\a
    d:\\aaa\\a\\a.java
    d:\\aaa\\a\\a.jpg
    d:\\aaa\\b
    d:\\aaa\\b\\B.JAVA
    d:\\aaa\\b\\b.avi
 */
public class Demo05Recursion {
    public static void main(String[] args) {
        File file = new File("d:\\aaa");
        getAllFile(file);
    }

    /*
        定义一个方法,参数传递要遍历文件夹
        方法内部对文件夹进行遍历
     */
    public static void getAllFile(File dir){
        File[] files = dir.listFiles();
        for (File file : files) {
            //判断遍历得到的file是否是一个文件夹
            if(file.isDirectory()){
                //file是一个文件夹,继续遍历这个文件夹
                //而我们发现getAllFile,就是一个传递文件夹,遍历文件夹的方法
                //调用getAllFile方法,传递文件夹即可
                getAllFile(file);// 方法自己调用自己==>递归
            }else{
                /*
                    需求:
                        只打印以.java结尾的文件
                    解决:
                        判断file是否是一个以.java结尾的文件,是则打印
                    实现步骤:
                        1.把file对象转换为String
                            a.file.toString()  "d:\aaa\aaa.java"
                            b.file.getPath()  "d:\aaa\aaa.java"
                            c.file.getName()   "aaa.java"
                        2.使用String类中的方法endsWith判断字符串是否以.java结尾
                        3.是.java结尾则打印
                 */
                /*String s = file.getName();//获取文件末尾名称
                String s1 = s.toLowerCase();//转换为小写
                boolean b = s1.endsWith(".java");//判断结尾是.java吗
                if(b){
                    System.out.println(file);
                }*/
                if(file.getName().toLowerCase().endsWith(".java")){
                    System.out.println(file);
                }
            }
        }
    }
}

三 IO概述

1.IO流概述和分类

在这里插入图片描述

2.一切皆为字节

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

四 字节流

1.字节输出流基本使用

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

/*
    java.io.OutputStream:字节输出流
        此抽象类是表示输出字节流的所有类的超(父)类。
        OutputStream里边定义了所有字节输出流中共性的成员方法,所有的子类都可以使用
    共性的成员方法:
        - public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
        - public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
        - public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
        - public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
        - public abstract void write(int b) :将指定的字节输出流。
    java.io.FileOutputStream:文件字节输出流 extends OutputStream
    构造方法:
        FileOutputStream(File file)
        FileOutputStream(String name)
        参数:输出的目的地
            File file:输出的目的地是一个文件
            String name:输出的目的地是一个文件路径
        构造方法的作用:
           1.会创建FileOutputStream对象
           2.会根据构造方法中传递的文件|文件路径,创建一个空白的文件
           3.会把FileOutputStream对象指向创建好的文件
    使用字节输出流往文件中写数据的底层过程
        java程序==>JVM==>操作系统(OS)==>调用系统中写数据的方法==>把数据写入到文件中
    字节输出流的使用步骤(重点):
        1.创建FileOutputStream对象,构造方法中绑定输出的目的地
        2.使用FileOutputStream对象中的方法write,把数据写入到文件中
        3.释放资源
 */
public class Demo01OutputStream {
    public static void main(String[] args) throws IOException {
        //1.创建FileOutputStream对象,构造方法中绑定输出的目的地
        FileOutputStream fos = new FileOutputStream("1220\\a.txt");
        //2.使用FileOutputStream对象中的方法write,把数据写入到文件中
        //public abstract void write(int b)一次写一个字节
        fos.write(97);
        //3.释放资源
        fos.close();
    }
}

在这里插入图片描述

2.字节输出流中写多个字节的方法

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

/*
    字节输出流中写多个字节的方法
        - public void write(byte[] b) 一次写字节数组中的多个字节到文件中
        - public void write(byte[] b, int off, int len) 一些写字节数组的一部分到文件中,off:数组的开始索引;len:写的字节个数
    ASCII:
        0:48
        A:65
        a:97
 */
public class Demo02OutnputStream {
    public static void main(String[] args) throws IOException {
        //1.创建字节输出流FileOutputStream对象,构造方法绑定输出的目的地
        FileOutputStream fos = new FileOutputStream(new File("1220\\b.txt"));
        //2.使用FileOutputStream对象中的方法write,把数据写入到文件中
        //public void write(byte[] b) 一次写字节数组中的多个字节到文件中
        /*
            一次写多个字节:
                第一个字节是负数,那么会和第二个字节组成一个中文
                第一个字节是正数,那么写出单个的字节
         */
        byte[] bytes = {65,66,67,68,69};//ABCDE
        //byte[] bytes = {-65,-66,-67,68,69};//烤紻E
        fos.write(bytes);

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

        //把字符串转换为字节数组,写入到文件中
        byte[] bytes1 = "中国".getBytes();
        System.out.println(Arrays.toString(bytes1));//[-28, -72, -83, -27, -101, -67] IDEA UTF-8编码
        fos.write(bytes1);//中国

        /*
            在文件中显示100
         */
        fos.write(49);//1
        fos.write(48);//0
        fos.write(48);//0

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

3.字节输出流续写和换行

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

/*
    字节输出流
    1.续写(追加写):使用两个参数的构造方法
        FileOutputStream(File file, boolean append)
        FileOutputStream(String name, boolean append)
        参数:
            File file,String name:写数据的目的地
            boolean append:追加写开关
                true:可以追加写,使用构造方法创建对象,不会覆盖之前的文件,会往文件的结尾继续写数据
                false:不可以续写,使用构造方法创建对象,文件名相同,会创建一个新的空白文件覆盖之前的文件
    2.换行:使用换行符号
        windows:\r\n
        linux:/n
        mac:/r  从 Mac OS X开始与Linux统一
 */
public class Demo03OutputStream {
    public static void main(String[] args) throws IOException {
        //创建FileOutputStream对象,构造方法中传递输出的目的地和追加写开关
        FileOutputStream fos = new FileOutputStream("1220\\c.txt",true);
        //使用FileOutputStream对象中的方法write,把数据写入到文件中
        for (int i = 1; i <= 10; i++) {
            fos.write(("你好"+i+"\n").getBytes());
        }
        //释放资源
        fos.close();
    }
}

4.字节输入流一次读取一个字节

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

/*
    java.io.InputStream:字节输入流
        此抽象类是表示字节输入流的所有类的超类。
        InputStream里边定义了所有字节输入流中共性的成员方法,所有字节输入流都可以使用
    共性的成员方法:
        - public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
        - public abstract int read(): 从输入流读取数据的下一个字节。
        - public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
    java.io.FileInputStream:文件字节输入流 extends InputStream
    作用:把文件中的数据,以字节的方式读取到内存中
    构造方法:
        FileInputStream(File file)
        FileInputStream(String name)
        参数:读取的数据源
            File file:读取的数据源是一个文件
            String name:读取的数据源是一个文件路径
        构造方法的作用:
            1.会创建FileInputStream对象
            2.会把创建好的FileInputStream对象指向要读取的文件的第一个字节
   使用字节输入流读取文件到内存中的底层原理:
        java程序==>JVM==>操作系统==>调用系统中读取数据的方法==>读取文件
   字节输入流的使用步骤(重点):
        1.创建FileInputStream对象,构造方法中绑定要读取的数据源
        2.使用FileInputStream对象中的方法read,以字节的方式读取文件
        3.释放资源
 */
public class Demo01InputStream {
    public static void main(String[] args) throws IOException {
        //1.创建FileInputStream对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("1220\\a.txt");//abc
        //2.使用FileInputStream对象中的方法read,以字节的方式读取文件
        //public abstract int read() 一次读取一个字节并返回
        /*
            我们发现读取文件,是一个重复的过程,所以可以使用循环优化
            不知道文件中有多少数据,使用while循环
            循环结束的条件,read方法读取到-1的时候结束

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


        /*int len = fis.read();
        System.out.println(len);//97

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

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

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

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

5.使用字节输入流一次读取多个字节

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

/*
    使用字节输入流一次读取多个字节
        public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
    明确两个内容
        1.read方法的参数byte[]字节数组是做什么用的?
            起到缓冲作用,可以把读取到的字节缓冲到数组中
            一次性的由操作系统返回给JVM,由JVM返回给java程序,效率高
            数组的长度一般都使用:1024或者1024的整数倍
        2.read方法的返回值int是什么?
            每次读取的有效字节个数
    String类的构造方法:
        String(byte[] bytes) 把字节数组转换为字符串
        String(byte[] bytes, int offset, int length) 把字节数组一部分转换为字符串
 */
public class Demo02InputStream {
    public static void main(String[] args) throws IOException {
        //创建字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
        FileInputStream fis = new FileInputStream("1220\\b.txt");//ABCDE
        //使用FileInputStream对象中的方法read,以字节的方式读取文件
        //public int read(byte[] b)使用数组缓冲一次读取多个字节
        /*
            我们发现读取数据,是一个重复的过程,所以可以使用循环优化
            不知道文件中有多少数据,使用while循环
            循环结束的条件,read方法读取到-1结束
         */
        byte[] bytes = new byte[1024];
        int len =0;
        while ((len = fis.read(bytes))!=-1){
            //System.out.println(Arrays.toString(bytes));
            //把字节数组的一部分转换为字符串
            System.out.println(new String(bytes,0,len));
        }


        /*byte[] bytes = new byte[2];
        int len = fis.read(bytes);
        //System.out.println(Arrays.toString(bytes));
        System.out.println(new String(bytes));//AB
        System.out.println(len);//2

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

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

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

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

在这里插入图片描述

6.文件复制案例

1).原理

在这里插入图片描述

2).代码实现

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

/*
    文件复制案例:
    原理:一读一写
    数据源: c:\\1.jpg
    目的地: d:\\1.jpg
    实现步骤:
        1.创建FileInputStream对象,绑定要读取的数据源
        2.创建FileOutputStream对象,绑定要写入的目的地
        3.使用FileInputStream对象中的方法read,以字节的方式读取文件
        4.使用FileOutputStream对象中的方法write,把读取到字节写入到文件中
        5.释放资源
 */
public class Demo01CopyFile {
    public static void main(String[] args) throws IOException {
        long s = System.currentTimeMillis();
        //1.创建FileInputStream对象,绑定要读取的数据源
        FileInputStream fis = new FileInputStream("c:\\1.exe");
        //2.创建FileOutputStream对象,绑定要写入的目的地
        FileOutputStream fos = new FileOutputStream("d:\\1.exe");
        //3.使用FileInputStream对象中的方法read,以字节的方式读取文件
        //一次读写一个字节,效率低下
        /*int len = 0;
        while ((len = fis.read())!=-1){
            //4.使用FileOutputStream对象中的方法write,把读取到字节写入到文件中
            fos.write(len);
        }*/

        //一次读写多个字节,效率高
        byte[] bytes = new byte[1024*100];
        int len = 0;
        while ((len = fis.read(bytes))!=-1){
            fos.write(bytes,0,len);
        }

        //5.释放资源
        fos.close();
        fis.close();
        long e = System.currentTimeMillis();
        System.out.println("复制文件共耗时:"+(e-s)+"毫秒!");
    }
}

五 字符流

1.使用字节输入流读取含有中文的文件

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

/*
    使用字节输入流读取含有中文的文件
        文件的编码GBK:一个中文占用2个字节
        文件的编码UTF-8:一个中文占用3个字节
 */
public class Demo01FileInputStream {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("1220\\e.txt");
        int len = 0;
        while ((len = fis.read())!=-1){
            System.out.print((char)len);//ÄãºÃ  使用字节流一次读取一个字节(1/2个中文),转换为字符,乱码
        }

       /* byte[]  bytes = new byte[3];
        int len = 0;
        while ((len = fis.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }*/

        fis.close();
    }
}

2.字符输入流的基本使用

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

/*
    java.io.Reader:字符输入流
    作用:一次读取一个字符
        用于读取字符流的抽象类。
        是所有字符输入流的最顶层的父类,里边定义了所有字符输入流中共性的成员方法,所有字符输入流都可以使用
    共性的成员方法:
        - public void close() :关闭此流并释放与此流相关联的任何系统资源。
        - public int read(): 从输入流读取一个字符。
        - public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
    java.io.FileReader:文件字符输入流 extends Reader
    作用:把文件中的字符读取到内存中
    构造方法:
        FileReader(File file)
        FileReader(String fileName)
        参数:要读取的数据源
            File file:要读取的数据源是一个文件
            String fileName:要读取的数据源是一个文件路径
        构造方法的作用:
            1.会创建一个FileReader对象
            2.会把FileReader对象指向要读取文件的第一个字符
    使用字符输入流读取文件的步骤(重点):
        1.创建FileReader对象,构造方法中绑定要读取的数据源
        2.使用FileReader中的方法read,以字符的方式读取文件
        3.释放资源
    String类的构造方法
        String(char[] value) 把字符数组转换为字符串
        String(char[] value, int offset, int count) 把字符数组的一部分转换为字符串
            参数:
                int offset:数组的开始索引
                int count:转换的个数
 */
public class Demo01Reader {
    public static void main(String[] args) throws IOException {
        //1.创建FileReader对象,构造方法中绑定要读取的数据源
        FileReader fr = new FileReader("1220\\e.txt");
        //2.使用FileReader中的方法read,以字符的方式读取文件
        //public int read() 一次读取一个字符
        /*int len = 0;
        while ((len = fr.read())!=-1){
            System.out.print((char)len);
        }*/

        //public int read(char[] cbuf)使用数组缓冲一次读取多个字符
        char[] chars = new char[1024];
        int len=0;
        while ((len =fr.read(chars))!=-1){
            System.out.println(new String(chars,0,len));
        }
        //3.释放资源
        fr.close();
    }
}

3.字符输出流的基本使用

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

/*
    java.io.Writer:字符输出流
        是所有字符输出流最顶层的父类,里边定义了所有字符输出流中共性的成员方法,所有的字符输出流都可以使用
    共性的成员方法:
        - public abstract void close() :关闭此流,但要先刷新它。
        - public abstract void flush() :刷新此输出流并强制任何缓冲的输出字符被写出。
        - public void write(int c) :写出一个字符。
        - public void write(char[] cbuf):将 b.length字符从指定的字符数组写出此输出流。
        - public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。
        - public void write(String str) :写出一个字符串。
        - void write(String str, int off, int len) 写入字符串的某一部分。
    java.io.FileWriter:文件字符输出流 extends Writer
    作用:把内存中的字符,写入到文件中
    构造方法:
        FileWriter(File file)
        FileWriter(String fileName)
        参数:写入数据的目的地
             File file:目的地是一个文件
             String fileName:目的地是一个文件路径
        构造方法的作用:
            1.创建一个FileWriter对象
            2.会根据构造方法中传递的文件|文件路径,创建一个新的空白的文件
            3.会把FileWriter对象,指向空白的文件
   字符输出流的使用步骤(重点):
        1.创建FileWriter对象,构造方法中绑定要写入的目的地
        2.使用FileWriter对象中的方法write,把数据写入到内存缓冲区中
        3.使用FileWriter对象中的方法flush,把内存缓冲中的数据刷新到文件中
        4.释放资源(会先调用flush方法,把数据刷新到文件中,在释放资源)
 */
public class Demo01Writer {
    public static void main(String[] args) throws IOException {
        //1.创建FileWriter对象,构造方法中绑定要写入的目的地
        FileWriter fw = new FileWriter("1220\\1.txt");
        //2.使用FileWriter对象中的方法write,把数据写入到内存缓冲区中
        //public void write(int c) :写出一个字符。
        fw.write(100);
        //3.使用FileWriter对象中的方法flush,把内存缓冲中的数据刷新到文件中
        //fw.flush();
        //4.释放资源(会先调用flush方法,把数据刷新到文件中,在释放资源)
        fw.close();
    }
}

4.关闭和刷新的区别

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

/*
    关闭和刷新的区别
        - flush :刷新缓冲区,把缓冲区中的数据刷新到文件,流对象可以继续使用。
        - close :关闭流,释放系统资源。关闭前会刷新缓冲区。把缓冲区中的数据刷新到文件,关闭之后流对象就不能使用了
 */
public class Demo02Writer {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("1220\\2.txt");
        fw.write(65);//A
        fw.write(66);//B
        fw.flush();//把缓冲区中的数据刷新到文件,流对象可以继续使用
        fw.write(67);//C
        fw.close();//把缓冲区中的数据刷新到文件,流对象就关闭了,就不能在使用了
        fw.write(68);//IOException: Stream closed
    }
}

5.字符流写字符的其他方法

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

/*
    写字符的其他方法:
        - public void write(int c) :写出一个字符。
        - public void write(char[] cbuf):将 b.length字符从指定的字符数组写出此输出流。
        - public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。
        - public void write(String str) :写出一个字符串。
        - void write(String str, int off, int len) 写入字符串的某一部分。
 */
public class Demo03Writer {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("1220\\3.txt");

        //public void write(char[] cbuf) 写字符数组中的多个字符
        char[] cs = {'a','b','c','d','中','国'};
        fw.write(cs);//abcd中国

        /*
            public abstract void write(char[] b, int off, int len) 写字符数组的一部分
                int off:数组的开始索引
                int len:写个数
         */
        fw.write(cs,4,2);//中国

        //public void write(String str) :写出一个字符串。
        fw.write("我是一个中国人,我骄傲!");

        //void write(String str, int off, int len) 写入字符串的某一部分。
        fw.write("我是一个中国人,我骄傲!",0,7);

        fw.close();
    }
}

5.字符输出流续写和换行

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

/*
    字符输出流
    1.续写(追加写):使用两个参数的构造方法
        FileWriter(File file, boolean append)
        FileWriter(String fileName, boolean append)
        参数:
            File file,String fileName:写数据的目的地
            boolean append:追加写开关
                true:可以追加写,使用构造方法创建对象,不会覆盖之前的文件,会往文件的结尾继续写数据
                false:不可以续写,使用构造方法创建对象,文件名相同,会创建一个新的空白文件覆盖之前的文件
    2.换行:使用换行符号
        windows:\r\n
        linux:/n
        mac:/r  从 Mac OS X开始与Linux统一
 */
public class Demo04Writer {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("1220\\4.txt",true);
        for (int i = 1; i <= 10; i++) {
            fw.write("hello"+i+"\r\n");
        }
        fw.close();
    }
}

字符流和字节流区别

1.使用字节流读写任意的文件:任何文件都是以字节为基本单位的

使用字节流读取含有中文的文件使用,一次读取一个字节(1/2,1/3中文),使用起来不方便

2.使用字符读写文本文件:使用记事本打开能看懂的文件 一次读写一个字符

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值