1.前言

存储数据的方案:

File_递归

有四种存储数据的方法:变量、数组、对象、集合。

共有特点:都是内存中的数据容器。在断电、程序终止时会丢失。

想要长久保存需要放到文件或者数据库中,存储在硬盘中,File类就是帮助我们来执行这个操作的。

2.File

File时Java.io.包下的类,File的对象,用于代表当前操作系统的文件或文件夹。

File只能对文件本身进行操作,不能读取文件里存储的数据

使用IO流可以读写文件或数据。将磁盘里的数据读到内存中。

3.使用

创建File类的对象

File_递归_02

public class test {
    public static void main(String[] args) {
        // 1. 创建一个File对象。指代某个具体的文件。
        // 路径分隔符
        // File f1 = new File("D:/resource/ab.txt");
        // File f1 = new File("D:\\resource\\ab.txt");

        File f1 = new File("D:" + File.separator + "resource" + File.separator + "ab.txt");
        System.out.println(f1.length()); // 文件大小
        
        // 注意:File对象可以指代一个不存在的文件路径
        File f3 = new File("D:/resource/aaaa.txt");
        System.out.println(f3.length());
        System.out.println(f3.exists()); // false

        // 想指定定位的文件在模块中。应该怎么定位?
        // 绝对路径: 带盘符的
        // File f4 = new File("D:\\code\\javasepromax\\file-io-app\\src\\a.txt");
        // 相对路径 (建议):不带盘符,默认从工程目录下寻找文件的。
        File f4 = new File("file-io-app\\src\\a.txt");//从模块名开始
        System.out.println(f4.length());
    }
}

有三种路径分隔符。

判断文件类型、获取文件信息

File_当前目录_03

// 7. public long lastModified():获取文件的最后修改时间。
File f1 = new File("D:/resource/ab.txt");
long time = f1.lastModified();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println(sdf.format(time));

// 8. public String getPath():获取创建文件对象时给的路径
File f2 = new File("D:/resource/ab.txt");
File f3 = new File("file-io-app\\src\\a.txt");
System.out.println(f2.getPath());
System.out.println(f3.getPath());

// 9. public String getAbsolutePath():获取绝对路径
System.out.println(f2.getAbsolutePath());
System.out.println(f3.getAbsolutePath());

创建和删除文件夹

File_System_04

public class test {
    public static void main(String[] args) throws Exception {
        // 1. public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true,反之。
        File f1 = new File("D:/resource/itheima2.txt");
        System.out.println(f1.createNewFile());

        // 2. public boolean mkdir():用于创建文件夹,注意:只能创建一级文件夹
        File f2 = new File("D:/resource/aaa");
        System.out.println(f2.mkdir());

        // 3. public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
        File f3 = new File("D:/resource/bbb/ccc/ddd/eee/fff/ggg");
        System.out.println(f3.mkdirs());

        // 4. public boolean delete():删除文件或者空文件夹,注意:不能删除非空文件夹
        System.out.println(f1.delete());
        System.out.println(f2.delete());

        File f4 = new File("D:/resource");
        System.out.println(f4.delete());
    }
}

遍历文件夹

File_System_05

public class test {
    public static void main(String[] args) {
        // 1. public String[] list():获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回。
        File f1 = new File("D:\\course\\特研内容");
        String[] names = f1.list();
        for (String name : names) {
            System.out.println(name);
        }

        // 2. public File[] listFiles():(重点)获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
        File[] files = f1.listFiles();
        for (File file : files) {
            System.out.println(file.getAbsolutePath());
        }
    }
}

File_System_06

4.多级遍历

方法递归(recursion)

递归是一种算法,在程序审设计语言中广泛使用。

从形式上说,方法调用自身的形式称为方法递归。分为直接递归和间接递归,前者是方法调用自己,后者是方法先调用其他方法,再由其他方法调用回去。

public class RecursionTest1 {
    public static void main(String[] args) {
        test1();
    }

    // 直接方法递归
    public static void test1() {
        System.out.println("---test1---");
        test1(); // 直接方法递归
    }

    // 间接方法递归
    public static void test2() {
        System.out.println("---test2---");
        test3();
    }

    public static void test3() {
        test2(); // 间接递归
    }
}

注意:递归如果没有控制好终止的话,会出现递归死循环,导致栈内存溢出错误

案例:求阶乘

public class test {
    public static void main(String[] args) {
        System.out.println("5的阶乘是:" + f(5));
    }

    public static int f(int n) {
        // 终结点
        if (n == 1) {
            return 1;
        } else {
            return f(n - 1) * n;
        }
    }
}

案例:文件搜索

从D盘中,搜索QQ.exe文件,找到后输出位置。

public class test {
    public static void searchFile(File dir, String fileName) {
        // 1. 定制合法的前提提搜金定
        if (dir == null || !dir.exists() || dir.isFile()) {
            return; // 代表无法搜索
        }

        // 2. dir不是null, 存在,一定是目录对象。
        // 获取当前目录下的全部一级文件对象。
        File[] files = dir.listFiles();

        // 3. 判断当前目录下是否存在有一级文件对象,以及是否可以获取到一级文件对象。
        if (files != null && files.length > 0) {
            // 4. 遍历全部一级文件对象。
            for (File f : files) {
                // 5. 判断当前是是否是文件, 还是文件夹
                if (f.isFile()) {
                    // 是文件,判断这个文件名是否是我们要找的
                    if (f.getName().contains(fileName)) {
                        System.out.println("找到了:" + f.getAbsolutePath());
                    }
                } else {
                    // 是文件夹,继续重复这个过程(递归)
                    searchFile(f, fileName);
                }
            }
        }
    }

    public static void main(String[] args) {
        File dir = new File("D:\\course");
        searchFile(dir, "目标文件名");
    }
}

案例:删除文件或文件夹

public class test {
    public static void deleteDir(File dir) {
        if (dir == null || !dir.exists()) {
            return;
        }

        if (dir.isFile()) {// 是文件,直接删除
            dir.delete();
            return;
        }

        // 1. dir存在且是文件夹,拿里面的一 级文件对象
        File[] files = dir.listFiles();
        if (files == null) {
            return;
        }

        // 2. 这是一个有内容的文件夹,干掉里面的内容,再干掉自己。
        for (File file : files) {
            if (file.isFile()) {
                file.delete();
            } else {
                deleteDir(file);
            }
        }

        dir.delete();
    }

    public static void main(String[] args) {
        File dir = new File("D:\\要删除的目录");
        deleteDir(dir);
    }
}

案例:啤酒问题

/**
 * 啤酒两元一瓶,两个空瓶可以换一瓶啤酒,四个盖子也可以换一瓶啤酒,十元可以喝几瓶。
 */
public class BottleExchange {
    static int totalNumber = 0; // 总买瓶数
    static int lastCoverNumber = 0; // 剩余盖子数
    static int lastBottleNumber = 0; // 剩余瓶子数

    public static void main(String[] args) {
        int initialMoney = 10; // 初始金额
        buy(initialMoney);
        System.out.println("总数数:" + totalNumber);
        System.out.println("剩余盖子数:" + lastCoverNumber);
        System.out.println("剩余瓶子数:" + lastBottleNumber);
    }

    public static void buy(int money) {
        // 1. 先买啤酒
        int buyNumber = money / 2;
        totalNumber += buyNumber;

        // 2. 把盖子和瓶子换成钱继续买
        // 计算本轮总的瓶子和瓶盖数
        int allBottleNumber = buyNumber + lastBottleNumber;
        int allCoverNumber = buyNumber + lastCoverNumber;

        int allMoney = 0;

        if (allBottleNumber >= 2) {
            allMoney += (allBottleNumber / 2) * 2;
            lastBottleNumber = allBottleNumber % 2;
        }

        if (allCoverNumber >= 4) {
            allMoney += (allCoverNumber / 4) * 2;
            lastCoverNumber = allCoverNumber % 4;
        }

        if (allMoney >= 2) {
            buy(allMoney);
        }
    }
}