A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

    今天我们进入java中IO的学习,File类可以操作磁盘上的文件,递归是常用的一种思想,把无法解决的大问题拆分成容易解决的小问题。
    以下是今天的学习目标
  • 能够说出File对象的创建方式
  • 能够说出File类获取名称的方法名称
  • 能够说出File类获取绝对路径的方法名称
  • 能够说出File类获取文件大小的方法名称
  • 能够说出File类判断是否是文件的方法名称
  • 能够说出File类判断是否是文件夹的方法名称
  • 能够辨别相对路径和绝对路径
  • 能够遍历文件夹
  • 能够解释递归的含义
  • 能够使用递归的方式计算5的阶乘
  • 能够说出使用递归会内存溢出隐患的原因

    以下是今天的详细笔记:
File类File类概述java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作

我们可以对File进行的操作:
        创建文件/目录
        删除文件/目录
        获取文件/目录
        判断文件/目录是否存在
        对目录进行遍历
        获取文件的大小
       
重要英文单词的含义: (起变量名时会用到)
        file: 文件
        directory: 目录
        path: 路径
File类的静态成员变量
java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
        // 静态成员变量
    static String pathSeparator: 路径分隔符的字符串形式
    static char pathSeparatorChar: 路径分隔符的char形式
            Windows系统是 分号;  
        Linux系统是 冒号:
    static String separator: 文件名称分隔符的字符串形式
    static char separatorChar: 文件名称分隔符的char形式
            Window系统是 反斜杠\
        Linux系统是 正斜杠/
绝对路径和相对路径
绝对路径:
        以盘符开始的路径
        如: "D:\\a\\hi.txt"
相对路径:
        不以盘符开始的简化路径. 相对于项目的根目录
        如: "a\\1.mp3", "123.txt"

注意事项:
        1. 路径不区分大小写 (在Windows系统中不区分大小写, Linux, Mac区分)
        2. 路径一般写成字符串, 而字符串中一个\是转义, 所以要写两个\\
File类: 构造方法
java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
        // 构造方法(创建了File对象, 并将其指向该路径. 不会真正在磁盘上创建这个文件)
        File File(String pathname): 根据 路径字符串 封装一个File对象
        File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
        File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象
5分钟练习: 测试构造方法
需求:
测试File类的构造方法:
        File File(String pathname): 根据 路径字符串 封装一个File对象
        File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
        File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // File File(String pathname): 根据 路径字符串 封装一个File对象
        File f1 = new File("z:\\z.txt");  // 不存在的路径也可以创建File对象
        System.out.println(f1);

        // File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
        File f2 = new File("a\\", "a.txt");  // 相对路径也可以
        System.out.println(f2);

        // File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象
        File f3 = new File(new File("d:\\"), "d.txt");
        System.out.println(f3);

        // 创建File对象后, 并不会在磁盘上创建文件或目录!
    }
}

File类: 获取方法
java.io.File类
    // 常用获取方法
    String getAbsolutePath(): 返回此File的绝对路径名字符串
    String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
    String getName(): 获取File对象的文件名或目录名
    long length(): 获取File表示的文件大小的字节数 (不能获取目录的大小)
5分钟练习: 测试获取方法
需求:
测试File类的获取方法:
        String getAbsolutePath(): 返回此File的绝对路径名字符串
    String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
    String getName(): 获取File对象的文件名或目录名
    long length(): 获取File表示的文件大小的字节数 (不能获取目录的大小)
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // String getAbsolutePath(): 返回此File的绝对路径名字符串
        File f1 = new File("a.txt");
        System.out.println(f1.getAbsolutePath());  // File对象是相对路径, 该方法可以获取到绝对路径
        
        // String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
        System.out.println(new File("a.txt").getPath());  // 创建对象时是什么路径, 获取的就是什么
        System.out.println(new File("d:\\a.txt").getPath());

        // String getName(): 获取File对象的文件名或目录名
        File f3 = new File("a\\b\\c\\d.txt");
        System.out.println(f3.getName());

        // long length(): 获取File表示的文件大小的字节数 (不能获取目录的大小)
        File f4 = new File("day08\\src\\com\\itheima\\test02\\Test.java");  // 相对路径
        System.out.println(f4.length());  // 1431
    }
}

File类: 判断方法
java.io.File类
    // 常用判断方法
        boolean exists(): 判断File对象代表的文件或目录是否实际存在
        boolean isDirectory(): 判断File表示的是否为目录
        boolean isFile(): 判断File表示的是否为文件
5分钟练习: 测试判断方法
需求:
测试File类的判断方法
        boolean exists(): 判断File对象代表的文件或目录是否实际存在
        boolean isDirectory(): 判断File表示的是否为目录
        boolean isFile(): 判断File表示的是否为文件
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // boolean exists(): 判断File对象代表的文件或目录是否实际存在
        File f1 = new File("day08\\src");
        System.out.println(f1.exists());

        // boolean isDirectory(): 判断File表示的是否为目录
        File f2 = new File("day08\\src\\com\\itheima\\test03");
        System.out.println(f2.isDirectory());

        // boolean isFile(): 判断File表示的是否为文件
        File f3 = new File("day08\\src\\com\\itheima\\test03\\Test.java");
        System.out.println(f3.isFile());
    }
}

File类: 创建删除方法
java.io.File类
    // 常用创建删除方法
        boolean createNewFile(): 当文件不存在时, 创建一个新的空文件
        boolean delete(): 删除由此File表示的文件或目录. (删除目录时必须是空目录)
        boolean mkdir(): 创建File表示的目录
        boolean mkdirs(): 创建File表示的多级目录
5分钟练习: 测试创建删除方法
需求:
在当前的模块中创建a目录(注意用相对路径时加上模块名), 在a目录中创建b目录
然后在b目录中创建b.txt文件和c.txt文件
删除c.txt文件
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) throws IOException {
        // 在当前的模块中创建a目录
       /* File dirA = new File("day08\\a");
        dirA.mkdir();

        // 在a目录中创建b目录
        File dirB = new File("day08\\a\\b");
        dirB.mkdir();*/

        // 以上两步可以合并为一步
        File dirAB = new File("day08\\a\\b");
        dirAB.mkdirs();

        // 在b目录中创建b.txt文件和c.txt文件
        File fileB = new File("day08\\a\\b\\b.txt");
        fileB.createNewFile();
        File fileC = new File("day08\\a\\b\\c.txt");
        fileC.createNewFile();

        // 删除c.txt文件
        fileC.delete();
        
        boolean result = new File("z:\\a").mkdirs();  // 磁盘不存在, 不会创建
        System.out.println(result);  // false
    }
}

File类: 遍历目录方法
java.io.File类
    // 常用获取目录中内容的方法
        String[] list(): 获取当前File目录下的所有子文件或目录的名字数组
        File[] listFiles(): 获取当前File目录中的所有子文件或目录的File对象数组
       
注意:
        只能用表示目录的File对象调用
        用文件的File对象, 或者路径不存在, 调用会报错
5分钟练习: 测试遍历目录方法
需求:
利用listFiles()遍历目录方法, 将当前模块中的文件或目录打印出来
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // 创建File对象指向当前模块
        File module = new File("day08");

        // listFiles()获取当前目录中的子文件和子目录的File数组
        File[] files = module.listFiles();
        for (File file : files) {
            System.out.println(file);
        }

        // list(): 获取当前目录中的子文件和子目录的文件名数组
        String[] list = module.list();
        for (String s : list) {
            System.out.println(s);
        }
    }
}

递归递归的概念, 分类, 注意事项
递归思想:
        遇到一个问题时, 将该问题拆解成可以解决的小问题, 如果解决不了, 继续拆解为更小的问题. 如果小问题解决了, 大问题也就能够解决

Java中实现递归的方式:
        方法内部调用方法自己 (所以必须定义方法)

递归的分类:
        直接递归: 方法自己调用方法
        间接递归: A方法调用B方法, B方法调用C方法, C方法调用A方法

递归时的注意事项:
    1. 递归要有限定条件(出口), 保证递归能够停止(就是在某种情况下方法不再调用自己), 否则会栈内存溢出
    2. 递归次数不能太多, 否则会栈内存溢出
    3. 构造方法不能递归

递归的使用前提:
        调用方法时, 方法的主体不变, 但每次传递的参数值不同, 可以使用递归
练习: 递归计算1~n的和5分钟练习: 递归求和
需求: 求1~n的和  1~5 1+2+3+4+5
分析:
        求1~5的和: 5+4+3+2+1
                                5~1的和 = 5 + (4~1的和)
                                        4~1的和 = 4 + (3~1的和)
                                                3~1的和 = 3 + (2~1的和)
                                                        2~1的和 = 2 + (1~1的和)
                                                                1~1的和 = 1;
                                                               
        把解决不了的问题, 定义成方法 (定义方法求5~1的和)
                如果小问题能解决, 直接写代码实现
                如果小问题不能解决, 就递归调用方法实现
                                                               
        求1~n的和: n+(n-1)+...+2+1
                                n~1的和 = n + ((n-1)~1的和)
                                        (n-1)~1的和 = (n-1) + ((n-1-1)~1的和)
                                                ...
                                                        2~1的和 = 2 + (1~1的和)
                                                                1~1的和 = 1;
递归实现思路
        将要解决的问题, 封装为方法
                求1~n的和: 定义方法
                getSum(n);
                getSum(n-1)
                getSum(1);
                private static int getSum(int n) {  // 解决问题: 求n~1的和
                        // 出口(方法自己不再调用自己)
                        if (n == 1) {
                return 1;
                        }
             return n + getSum(n-1);
                }
        在方法内部, 拆解问题, 不能解决的小问题, 继续递归调用方法
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        int sum1 = sum(3);  // 6
        int sum2 = sum(5);  // 15
        System.out.println(sum1);
        System.out.println(sum2);
    }

    // 定义方法: 求n到1的和
    public static int sum(int n) {
        // 出口
        if (n == 1) {
            return 1;  // 问题不再能拆解为更小的问题, 直接解决
        }
        // 如果不能直接解决, 则拆分为能解决的小问题和不能解决的小问题
        // 能解决的小问题直接写代码
        // 不能解决的小问题递归调用方法解决
        return n + sum(n - 1);
    }
}

练习: 递归求n的阶乘5分钟练习: 递归求阶乘
阶乘: 一个数一直乘到1的积5的阶乘: 5 * 4 * 3 * 2 * 1 乘积需求: 使用递归计算5的阶乘分析:        5! = 5* 4*3*2*1             5* 4!                4! = 4* 3!                        3! = 3* 2!                                2! = 2* 1!                                        1! = 1  问题全都解决        n! = n* (n-1)!                (n-1)! = n-1 * (n-2)!                        ...                                2! = 2* 1!                                1! = 1  问题全都解决                                递归实现思路        将要解决的问题, 封装为方法        求n的阶乘               
[Java] 纯文本查看 复制代码
private static int jc(int n) {			//出口
			if (n == 1) {
                return 1;
			}
              return n * jc(n-1);
		}
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        int jc = jc(5);
        System.out.println(jc);  // 120
    }

    // 计算n的阶乘
    public static int jc(int n) {
        // 出口
        if (n == 1) {
            return 1;  // 能解决问题, 直接写代码
        }
        // 如果不能解决, 则拆解问题
        return n * jc(n-1);
    }
}
练习: 递归打印多级目录5分钟练习: 递归打印多级目录
需求: 打印当前模块目录下的所有文件和目录路径 (包含子目录)

aaa/
|_ bbb/
|        | ccc/
|        |        |_ c1.java
|        |       
|        |_ b1.java
|        |_ b2.java
|
|_ a1.java
|_ a2.java

递归思想拆分问题:
大问题:
打印aaa目录中子文件和子目录的路径 =
           打印a1,a2子文件路径
        && 打印bbb子目录路径
        && 打印bbb子目录中子文件和子目录的路径?
                打印bbb子目录中子文件和子目录的路径 =
                          打印b1,b2子文件路径
            && 打印ccc子目录路径
            && 打印ccc子目录中子文件和子目录的路径?
                    打印ccc子目录中子文件和子目录的路径 =
                            打印b1,b2子文件路径

出口? 一个目录中不再有子目录
要定义的方法: 打印某个目录中子文件和子目录的路径
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        File dir = new File("day08");
        print(dir);
    }

    // 定义方法: 打印某个目录中所有路径
    public static void print(File dir) {  // 传入要打印的目录的File对象
        // 先打印当前目录的路径
        System.out.println(dir);

        // 获取当前目录中的所有子文件和子目录
        File[] files = dir.listFiles();
        // 遍历数组
        for (File file : files) {
            // file代表子文件或者子目录, 具体是什么还需要判断
            if (file.isFile()) {
                // 如果是文件, 则打印文件
                System.out.println(file);
            } else {
                // 如果是目录, 则递归调用当前方法, 打印"该子目录"中的所有路径
                print(file);  // 注意传入的是子目录对象!!!!!
            }
        }
    }
}

综合案例综合案例之多级目录搜索5分钟练习: 递归遍历多级目录
补充String类中的方法:
        boolean endsWith(String suffix): 判断字符串是否以指定的字符串结尾
        String toLowerCase(): 将字符串转为小写字母
                String s = "AAAaaa".toLowerCase();
                s: "aaaaaa"
       
        aaa.java   文件名
        file.getName()  boolean b = "aaa.java".endsWith(".java");
需求: 打印当前模块中的.java文件 (包含子目录)

aaa/
|_ bbb/
|        | ccc/
|        |        |_ c1.java
|        |       
|        |_ b1.java
|        |_ b2.txt
|
|_ a1.java
|_ a2.txt

递归思想分析:
大问题: 打印aaa目录下的所有java文件路径 = 打印a1.java && 打印bbb目录下的所有java文件路径?
                打印bbb目录下的所有java文件路径 = 打印b1.java && 打印ccc目录下的所有java文件路径?
                        打印ccc目录下的所有java文件路径 = 打印c1.java
                       
出口? 某个目录下不再有子目录
定义方法: 打印某个目录下所有java文件路径

代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        print(new File("day08"));
    }

    // 定义方法: 打印某个目录中的.java文件
    public static void print(File dir) {
        // 先获取当前目录中的所有文件
        File[] files = dir.listFiles();
        // 遍历
        for (File file : files) {
            // 判断是文件还是目录
            if (file.isFile()) {
                // 是文件, 判断后缀
                if (file.getName().toLowerCase().endsWith(".java")) {
                    // 是java文件, 打印
                    System.out.println(file);
                }
            } else if (file.isDirectory()) {
                // 是目录, 递归调用方法
                print(file);
            }
        }
    }
}

FileFilter文件过滤器的原理和使用
java.io.File类:  Filter过滤器
        File[] listFiles(FileFilter filter): 通过File对象过滤, 返回文件过滤器过滤后的File对象数组
        File[] listFiles(FilenameFilter filter): 通过File对象的文件名过滤, 返回文件过滤器过滤后的File对象数组

java.io.FileFilter接口: 用于File对象的过滤器
        boolean accept(File pathName): true则会将参数的File对象加入返回的File[], false则不加入

java.io.FilenameFilter接口:
        boolean accept(File dir, String name): true则会将参数的File对象加入返回的File[], false则不加入
5分钟练习: 使用FileFilter
需求:
使用File[] listFiles(FileFilter filter)方法, 将当前模块中的.java文件过滤出来, 打印到控制台
代码:
[Java] 纯文本查看 复制代码
public class JavaFileFilter implements FileFilter {
    @Override
    public boolean accept(File pathname) {
        // 如果是目录, 则加入结果
        if (pathname.isDirectory()) {
            return true;
        }
        // 如果不是目录, 则判断以.java结尾的也加入结果
        return pathname.getName().toLowerCase().endsWith(".java");
    }
}

public class Test {
    public static void main(String[] args) {
        print(new File("day08"));
    }

    // 打印指定目录中的.java文件
    public static void print(File dir) {
        // 获取当前目录中的所有符合要求的文件, 传递文件过滤器
        File[] files = dir.listFiles(new JavaFileFilter());
        // 遍历
        for (File file : files) {
            if (file.isFile()) {
                // 如果是文件, 则直接打印, 因为已经过滤好了
                System.out.println(file);
            } else if (file.isDirectory()) {
                // 如果是目录, 则递归调用方法打印内部的java文件
                print(file);
            }
        }
    }
}

FileFilter文件过滤器的使用和Lambda优化
5分钟练习: 使用Lambda表达式优化搜索代码需求:
使用File[] listFiles(FilenameFilter filter)方法和Lambda表达式, 将当前模块下的.java文件过滤打印出来
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        print(new File("day08"));
    }

    // 打印指定目录中的.java文件
    public static void print(File dir) {
        // 获取当前目录中的文件, 使用过滤器
        /*File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return new File(dir, name).isDirectory() || name.toLowerCase().endsWith(".java");
            }
        });*/

        // 使用Lambda表达式简化
        File[] files = dir.listFiles((d, name) -> new File(d, name).isDirectory() || name.toLowerCase().endsWith(".java"));

        // 遍历
        for (File file : files) {
            if (file.isFile()) {
                // 是文件, 则打印
                System.out.println(file);
            } else if (file.isDirectory()) {
                // 是目录, 则递归
                print(file);
            }
        }
    }
}

今日API
java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
        // 静态成员变量
    static String pathSeparator: 路径分隔符的字符串形式
    static char pathSeparatorChar: 路径分隔符的char形式
            Windows系统是 分号;  
        Linux系统是 冒号:
    static String separator: 文件名称分隔符的字符串形式
    static char separatorChar: 文件名称分隔符的char形式
            Window系统是 反斜杠\
        Linux系统是 正斜杠/
    // 构造方法(创建了File对象, 并将其指向该路径. 不会真正在磁盘上创建这个文件)
        File File(String pathname): 根据 路径字符串 封装一个File对象
        File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
        File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象
        // 常用获取方法
    String getAbsolutePath(): 返回此File的绝对路径名字符串
    String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
    String getName(): 获取File对象的文件名或目录名
    long length(): 获取File表示的文件大小的字节数 (不能获取目录的大小)
    // 常用判断方法
        boolean exists(): 判断File对象代表的文件或目录是否实际存在
        boolean isDirectory(): 判断File表示的是否为目录
        boolean isFile(): 判断File表示的是否为文件
        // 常用创建删除方法
        boolean createNewFile(): 当文件不存在时, 创建一个新的空文件
        boolean delete(): 删除由此File表示的文件或目录. (删除目录时必须是空目录)
        boolean mkdir(): 创建File表示的目录
        boolean mkdirs(): 创建File表示的多级目录
        // 常用获取目录中内容的方法
        String[] list(): 获取当前File目录下的所有子文件或目录的名字数组
        File[] listFiles(): 获取当前File目录中的所有子文件或目录的File对象数组
        File[] listFiles(FileFilter filter): 通过File对象过滤, 返回文件过滤器过滤后的File对象数组
        File[] listFiles(FilenameFilter filter): 通过File对象的文件名过滤, 返回文件过滤器过滤后的File对象数组

java.io.FileFilter接口: 用于File对象的过滤器
        boolean accept(File pathName): true则会将参数的File对象加入返回的File[], false则不加入

java.io.FilenameFilter接口:
        boolean accept(File dir, String name): true则会将参数的File对象加入返回的File[], false则不加入


























2 个回复

正序浏览
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马