Java文件操作-IO

一:文件

(1)概念

文件其实就是在硬盘上存储数据的方式


操作系统一般通过“文件系统”这样的模块来管理硬盘

(2)磁盘管理

①打开方式:右键windows徽章,里面有磁盘管理选项


②作用:可以看到自己的硬盘个数以及硬盘各部分区域

操作系统通过将硬盘分成许多区域,然后通过一定格式去组织硬盘上的数据


③Windows上的文件系统:NTFS 


④Linux上的文件系统:EXT4

(3)文件组织方式

💗通过“N叉树”的树型结构来组织


(4)文件路径

①绝对路径:以盘符开头的路径;相当于从此电脑出发寻找文件的过程

(盘符:英文字母加一个 ':')

例如:C:/inetpub/custerr


②相对路径:以.或者..开头的路径

(.表示当前目录;..表示当前目录的上一层目录)

(相对路径需要有一个基准目录/工作目录,表示从这个基准目录出发怎么样才能找到文件)


例如:我的D盘中的test目录下有个“1aA”照片

(1)假设我以D盘为基准目录,那么找到“1aA”照片的相对路径为./test/1aA.jpeg

(2)假设我以D:/test为基准目录,那么找到“1aA”照片的相对路径为./1aA.jpeg

(3)假设我以D:/test/tt为基准目录,那么找到“1aA”照片的相对路径为../1aA.jpeg

(5)文件类型

①文本文件:存储的是字符

②二进制文件:存储的是二进制


🌟如何判断是文本文件还是二进制文件?

方法:用记事本打开,看得懂的就是文本文件,看不懂的就是二进制文件

(用记事本打开文件,就是尝试把当前数据在码表中进行查询)

 

二:Java 中操作文件

(1)File类的基本概念

①包:属于java.io包

i:input输入

o:output输出


②作用:用来描述文件的信息、路径的操作

(暂不涉及关于文件中内容的读写操作)


③注意:File 对象是用来描述一个具体的对象,这个File对象可以对应一个真实存在的文件,也可以对应一个不存在的文件;因此,有 File 对象,并不代表真实存在该文件

(2)File类的构造方法

 (3)File类部分重要方法的演示

①String getParent():返回 File 对象的父目录文件路径(父目录就是上一层目录)

②String getName(): 返回 FIle 对象的纯文件名称

package file;
import java.io.File;
import java.io.IOException;

public class Demo1 {
    public static void main(String[] args)  {
        //并不要求该test.txt文件真实存在
        File file = new File("./test.txt");    //File()括号里初始化可以是相对路径也可以是绝对路径
        System.out.println(file.getParent());
        System.out.println(file.getName());
    }
}


③String getPath():返回 File 对象的文件路径

(文件路径是绝对路径还是相对路径取决于你初始化给File对象的是绝对还是相对)

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

public class Demo1 {
    public static void main(String[] args)  {
        File file = new File("./test.txt"); 
        System.out.println(file.getPath());  //因为我初始化给的是相对路径,所以一会打印的也是相对路径
    }
}


④String getAbsolutePath():返回 File 对象的绝对路径

(如果初始化是相对路径,那么就把初始化的相对路径拼接上当前路径返回)


⑤String getCanonicalPath():返回 File 对象的修饰过的绝对路径

(需要抛IOException异常)

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

public class Demo1 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getCanonicalPath());
    }
}

 


⑥boolean createNewFile():根据 File 对象的初始化,自动创建一个空文件

成功创建后返回 true

(需要抛IOException异常)


⑦boolean exists():判断 File 对象描述的文件是否真实存在

⑧boolean isDirectory():判断 File 对象代表的文件是否是一个目录

⑨boolean isFile():判断 File 对象代表的文件是否是一个普通文件


💖 (1)此时test.txt文件不存在
import java.io.File;
import java.io.IOException;

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");   //此时test.txt文件不存在

        System.out.println("没有创建文件时:");
        System.out.println(file.exists());
        System.out.println(file.isFile());
        System.out.println(file.isDirectory());
    }
}


💖 (2)此时test.txt文件创建了

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

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");   //此时test.txt文件不存在

        System.out.println("创建文件后:");
        file.createNewFile();   //创建test.txt文件
        System.out.println(file.exists());
        System.out.println(file.isFile());
        System.out.println(file.isDirectory());
    }
}

 


⑩boolean delete():根据 File 对象,删除该文件。成功删除后返回 true


⑪void deleteOnExit():根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行


⑫boolean mkdir():创建 File 对象代表的目录,只能创建一个目录


⑬boolean mkdirs():创建 File 对象代表的目录,可以创建多级目录

import java.io.File;

public class Demo3 {
    public static void main(String[] args) {
        File file1 = new File("./testDir1");
        File file2 = new File("./testDir/111/222/333");

        // mk => make    dir => directory

        // mkdir 一次只能创建一层目录
        file1.mkdir();

        //mkdirs 可以一次创建多级目录
        file2.mkdirs();
    }
}


⑭boolean renameTo(File dest):进行文件改名,同时也能起到文件移动的效果

(1)当两个文件名不同时,file1 renameTo(file2)就是将file1文件名改成file2文件名

(2)当两个文件名相同时,file1 renameTo(file2)就是将file1路径的文件移动到file2路径下


💚1.当两个文件名不同
import java.io.File;

public class Demo4 {
    public static void main(String[] args) {
        //file1和file2文件名不同,此时起到的作用就是file1文件名改成file2文件名
        File file1 = new File("./test.txt");
        File file2 = new File("./test1.txt");
        file1.renameTo(file2);
    }
}


 💚2.当两个文件名相同

import java.io.File;

public class Demo4 {
    public static void main(String[] args) {
        //file1和file2文件名相同,此时起到的作用就是file1文件移动到file2路径下
        File file1 = new File("./test.txt");
        File file2 = new File("./src/file/test.txt");
        file1.renameTo(file2);
    }
}

 

(4)File类的方法大全

 三:文件内容的读写-数据流

💗这部分涉及到关于文件中内容的读写操作

(1)数据流

①概念:指的是我们在操作文件的时候具体是想一次操作多少个字节

(我们是通过一系列的类来操作文件内容中的读写)


②字节流:主要通过InputStream、OuputStream这两个类的衍生来操作字节文件

以操作字节为单位

操作的是二进制文件


③字符流:主要通过Reader、Writer这两个类的衍生来操作字符文件

以操作字符为单位

操作的是文本文件


④Java IO流是一个比较庞大的体系,涉及到很多的类,这些不同的类,都有各自不同的特性,但是总的来说,使用方法都是类似的

(1)通过构造方法,创建和打开文件

(2)通过close方法,关闭文件(这个close方法上述四个类用法都是一样的)

(3)如果衍生自InputStream或者Reader,就可以使用read方法读取数据

(4)如果衍生自OuputStream或者Writer,就可以使用write方法写入数据

(2)close-释放必要资源

释放必要资源:close()


💛对于InputStream、OuputStream、Writer、Reader用法都一样


💚 注意:这个操作非常重要!我们需要知道,让进程打开一个文件,是要从系统这里申请一定的资源,也即是会占用PCB里的文件描述符表的一个表位,但其实文件描述符表它的表位是有限的,不会自动扩展,一旦你打开文件不释放,就会造成“文件资源泄露”,会导致文件描述符表位被占满,到时候就打不开文件了!


💙close使用方法一:try with resources;try代码全部执行完自动调用close,无需手动!

(手动添加有弊端,原因在于抛出异常,或者 return,close 就都执行不到了)

        // 使用 try with resources
        // 当try里面的代码执行完,就会自动帮你调用close,无需手动
        // 括号里面写对象的创建语句(可以是一条/多条)
        try(){

        }


💙close使用方法二:try-catch-finally;手动将close添加到finally里面(不太推荐)

(虽然finally最终还是会执行到close,但是这种方式我们不常用也不推荐)

        try {
            // 中间的代码无论出现啥情况, close 都能保证执行到.
        } finally {
            引用对象.close();
        }

(3)字符流-Reader(读)

①创建Reader对象

💚 注意:因为Reader是一个抽象类,我们使用FileReader类创建来一个Reader

💙FileReader构造方法:可以填写一个文件路径(绝对路径/相对路径都行), 也可以填写一个构造好的 File 对象

②Reader方法

🌟一般是配合循环使用,因为读数据不可能只读一个两个


(1)int read():读取一个字符的数据

(返回 -1 代表已经完全读完了)


(2)int read(char[] buf):把读到的所有以字符为单位的数据全部放入自定义的buf数组中;自定义buf数组给的初始化的值是字符为单位的数

(返回值是实际读到的数量)

(返回 -1 代表已经完全读完了)


(3)int read(char[] buf, int off, int len):从off下标开始,读取len个字符到数组buf中

(返回值是实际读到的数量)

(返回 -1 代表已经完全读完了)


import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

// Reader 使用.
 需要先在项目目录下准备好一个 hello.txt 的文件,里面填充 "Hello World" 的内容
public class Demo5 {
    public static void main(String[] args) throws IOException {
        //使用try with resources,代码执行完自动close
        try (Reader reader1 = new FileReader("./test.txt")) {
            while (true) {
                //自定义buf数组,1024个字符
                char buf[] = new char[1024];
                //将在test.txt中读到的内容放进且填充buf数组
                //返回实际读到的个数n
                int n = reader1.read(buf);
                System.out.println(n);
                if (n == -1) {
                    // 读到文件末尾了.
                    break;
                }
                for (int i = 0; i < n; i++) {
                    System.out.print(buf[i] + " ");  //打印读到的内容
                }
                System.out.println("\n");
            }
        }
    }
}

(4)字节流-InputStream(读)

 ①创建InputStream对象

💚 注意:因为InputStream是一个抽象类,我们使用FileInputStream类创建InputStream

💙FileInputStream构造方法:可以填写一个文件路径(绝对路径/相对路径都行), 也可以填写一个构造好的 File 对象 

②InputStream方法

🌟使用方法和Reader类似,且一般是配合循环使用

💓注意:InputStream虽然是字节流,但是同样可以读取字符,只不过是编码

(但同样可以采取一些措施来让这些编码变成文字,下文介绍)


(1)int read():读取一个字节的数据

(返回 -1 代表已经完全读完了)


(2)int read(byte[] buf):把读到的所有以字节为单位的数据全部放入自定义的buf数组中;自定义buf数组给的初始化的值是字节为单位的数

(返回值是实际读到的数量)

(返回 -1 代表已经完全读完了)


(3)int read(char[] buf, int off, int len):从off下标开始,读取len个字节到数组buf中

(返回值是实际读到的数量)

(返回 -1 代表已经完全读完了)


💝这里我们还是以读取字符为例(test.txt里面的内容是你好世界)

💙通过运行结果我们能看到,读取到的内容并非“你好世界”,而是一堆编码,这是因为字节流InputStream读取到的是文本的每个字节,因此,要想看到汉字,我们可以采取一些额外的工具类,例如String,以及下文提到的Scanner,这里我们用String的构造方法为例!

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

public class Demo6 {
    public static void main(String[] args) throws IOException {
        //test.txt里面的内容是你好世界
        //使用try with resources,代码执行完自动close
        try (InputStream inputStream = new FileInputStream("./test.txt")) {
            while (true) {
                //自定义buf数组,1024个字节
                byte[] buf = new byte[1024];
                int n = inputStream.read(buf);
                System.out.println(n);
                if (n == -1) {
                    // 读到文件末尾了.
                    break;
                }
                for (int i = 0; i < n; i++) {
                    System.out.printf("%x ", buf[i]);   //打印读取到的内容,一般我们用十六进制表示
                }
                System.out.println("\n");
            }
        }
    }
}


💛String构造方法让编码转化成文字

💚方法:String(数组名, 开始下标, 读取多少个, 字符编码);

🖤下面我们修改代码,只加了一条语句:

 


🌟虽然String可以修改,但是我们并不推荐,接下来介绍一下Scanner!!! 

(5)字符读取-Scanner(读)

①Scanner(InputStream inputstream)

💙对insputstream对象进行读取(没有指定字符集)

💜将构造好的InputStream对象作为Scanner的参数


②Scanner(InputStream inputstream, String charset)

💙使用 charset 字符集进行对insputstream对象进行读取

💜将构造好的InputStream对象作为Scanner的参数


③读取内容的方法:引用对象.next()、引用对象.nextInt()

💚跟以前控制台输入一样,看文本内容是什么就写什么


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class Demo7 {
    public static void main(String[] args) throws IOException {
        try (InputStream inputStream = new FileInputStream("./test.txt")) {
            //将构造好的InputStream对象放入Scanner中作为参数
            //指定字符集为UTF-8
            Scanner scanner = new Scanner(inputStream,"UTF-8");
            // 此时就是从 test.txt 这个文件中读取数据了!!
            String s = scanner.next();
            System.out.println(s);
        }
    }
}

(6)字符流-Writer(写)

①创建Writer对象

💚 注意:因为Writer是一个抽象类,我们使用FileWriter类创建Writer

💙FileWriter构造方法1:可以填写一个文件路径(绝对路径/相对路径都行), 也可以填写一个构造好的 File 对象 ,这种方法打开文件之后会清空之前的内容


💛FileWriter构造方法2:以追加的方式写为true,这样打开文件之后不会清空之前的内容

②Writer方法

🌟输出流对象(无论是字节流还是字符流),在打开文件之后会清空之前所有的内容


(1)void write(int c):写入一个数字


(2)void write(String str):写入一个字符串


①构造方法1:不追加的形式

🌟运行完成后可以看到之前的内容没有了 

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

public class Demo8 {
    public static void main(String[] args) throws IOException {
        //这种是以不追加方式的构造方法
        //test.txt原本具有你好世界的内容
        try (Writer writer = new FileWriter("./test.txt")) {
            // write 写一个字符串
            writer.write("hello java");
        }
    }
}

 


②构造方法2:以追加的形式

🌟运行完成后可以看到之前的内容依旧保留

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

public class Demo8 {
    public static void main(String[] args) throws IOException {
        //这种是以追加方式的构造方法
        //test.txt原本具有你好世界的内容
        try (Writer writer = new FileWriter("./test.txt",true)) {
            // write 写一个字符串
            writer.write("hello java");
        }
    }
}

(7)字节流-OutputStream(写)

①创建OutputStream对象

💚 注意:因为OutputStream是一个抽象类,我们用FileOutputStream创建OutputStream

💙FileOutputStream构造方法1:可以填写一个文件路径(绝对路径/相对路径都行), 也可以填写一个构造好的 File 对象 

💛FileOutputStream构造方法2:以追加的方式写为true,这样打开文件之后不会清空之前的内容

②OutputStream方法

💓注意:InputStream虽然是字节流,但是同样可以写入字符,只不过要强制类型转换成byte字节类型或者使用PrintWriter

🌟可以使用getBytes()方法将字符串转换为字节数组的方法

🌟getBytes()方法将字符串中的字符转换成byte类型并存储到byte数组中


(1)void write(int b):写入要给字节的数据


(2)void write(byte[] buf): 将buf这个字节数组中的数据全部写入OutputStream对象中


(3)int write(byte[] buf, int off, int len) :将buf这个字节数组中从off开始的下标写入到OutputStream对象中,一共写 len 个


(4)void flush()重要!!!我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为 了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的 一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写 入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的 数据,很可能会遗留一部分在缓冲区中。需要在代码的最后或者合适的位置, 调用 flush(刷新)操作,将数据刷到设备中


🌟代码1:

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

public class Demo9 {
    public static void main(String[] args) throws IOException {
        //这种是以追加方式的构造方法,不会清空原本内容
        try (OutputStream outputStream = new FileOutputStream("./test.txt",true)) {
            outputStream.write('H');
            outputStream.write('e');
            outputStream.write('l');
            outputStream.write('l');
            outputStream.write('o');
            // 不要忘记 flush!!!
            outputStream.flush();
        }
    }
}


 🌟代码2:

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

public class Demo9 {
    public static void main(String[] args) throws IOException {
        //这种是以追加方式的构造方法,不会清空原本内容
        try (OutputStream outputStream = new FileOutputStream("./test.txt",true)) {
            byte[] buf = new byte[] {
                    (byte)'G', (byte)'o', (byte)'o', (byte)'d'   //因为像Good这种是字符char型,要强制转成byte类型
            };
            outputStream.write(buf);
            // 不要忘记 flush!!!
            outputStream.flush();
        }
    }
}


 🌟代码3:

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

public class Demo9 {
    public static void main(String[] args) throws IOException {
        //这种是以追加方式的构造方法,不会情况原本内容
        try (OutputStream outputStream = new FileOutputStream("./test.txt",true)) {
            String s = "Nothing";
            //通过getBytes()方法将字符串中的字符转换成byte类型并存储到byte数组中
            byte[] buf = s.getBytes();
            outputStream.write(buf);
            // 不要忘记 flush!!!
            outputStream.flush();
        }
    }
}

(8)字符写入-PrintWriter(写)

①作用

💓PrintWriter 类中提供了我们熟悉的 print/println/printf 方法


💙OutputStream是字节流,本身应该写入的是字节类型的数据;当你想写入字符,又不想强制转换字节类型数组那样太麻烦了,就可以将OutputStream对象作为PrintWriter的参数,这样再调用print/println/printf 即可按照你需要的格式写入字符

②使用方法

1.将写好的OutputStream对象作为PrintWriter构造方法的参数

2.调用print/println/printf 方法

例如:

OutputStream outputStream = new FileOutputStream("./test.txt",true);

PrintWriter writer = new PrintWriter(outputStream);


// 接下来我们就可以方便的使用 writer 提供的各种方法了
writer.print("Hello");
writer.println("你好");
writer.printf("%d: %s\n", 1, "没什么");

// 不要忘记 flush
writer.flush();

四:练习巩固

(1)题目一

💓题目:扫描用户指定的目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件

🌟这个题目要求我们能够熟悉File类并且能够写出深度优先的代码!

💗contains(关键字):查看是否包含关键字

import java.io.File;
import java.util.Scanner;

public class Demo10 {
    private static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        // 1. 让用户输入一个目录. 后续的查找都是针对这个目录来进行的.
        System.out.println("请输入要搜索的根目录: ");
        File rootPath = new File(scanner.next());
        // 2. 再让用户输入要搜索/要删除的关键词.
        System.out.println("请输入要删除的关键词: ");
        String keyword = scanner.next();
        // 3. 判定一下当前输入的目录是否有效.
        if (!rootPath.isDirectory()) {
            System.out.println("您此时输入的路径不是合法目录!");
            return;
        }
        // 4. 遍历目录. 从根目录出发, 按照 深度优先(递归) 的方式, 进行遍历
        scanDir(rootPath, keyword);
    }

    public static void scanDir(File currentDir, String word) {    //扫描查找文件整体代码
        // 1. 先列出当前目录中都包含哪些内容,把内容放进files数组.
        File[] files = currentDir.listFiles();
        if (files == null || files.length == 0) {
            // 判断是不是空的目录或者非法的目录
            return;
        }
        // 2. 遍历列出的文件, 分两个情况分别讨论.
        //for-each循环,把files数组一个个放入f
        for (File f : files) {
            // 加个日志, 方便看程序执行的过程.
            System.out.println(f.getAbsolutePath());

            if (f.isFile()) {
                // 3. 如果当前文件是普通文件, 看看文件名是否包含了 word, 来决定是否要删除.
                dealFile(f, word);
            } else {
                // 4. 如果当前文件是目录文件, 就递归执行 scanDir
                scanDir(f, word);
            }
        }
    }

    private static void dealFile(File f, String word) {   //删除文件整体代码
        // 1. 先判定当前文件名是否包含 word
        if (!f.getName().contains(word)) {
            // 此时这个文件不包含 word 关键词. 直接跳过.
            return;
        }
        // 2. 包含 word 就需要询问用户是否要删除该文件?
        System.out.println("该文件是: " + f.getAbsolutePath() + ", 是否要确认删除? (Y/N)");
        String choice = scanner.next();
        if (choice.equals("Y") || choice.equals("y")) {
            f.delete();
        }
        // 如果是其他值, 都忽略.
    }
}

(2)题目二

💓题目:进行普通文件的复制

import java.io.*;
import java.util.Scanner;

// 完成文件复制.
public class Demo11 {
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        // 1. 输入路径并且合法性判定
        System.out.println("请输入要复制的源文件路径: ");
        String src = scanner.next();
        File srcFile = new File(src);   //直接将src路径构造成File对象
        if (!srcFile.isFile()) {
            System.out.println("您输入的源文件路径非法!");
            return;
        }
        System.out.println("请输入要复制到的目标路径: ");
        String dest = scanner.next();
        File destFile = new File(dest);  //直接将dest路径构造成File对象
        // 不要求目标文件本身存在. 但是得保证目标文件所在的目录, 得是存在的.
        // 假设目标文件写作 d:/tmp/cat2.jpg, 就需要保证 d:/tmp 目录是存在的.
        if (!destFile.getParentFile().isDirectory()) {
            System.out.println("您输入的目标文件路径非法!");
            return;
        }

        // 2. 进行复制操作的过程. 按照字节流打开.
        //打开源文件srcFile,往目标路径destFile写入
        try (InputStream inputStream = new FileInputStream(srcFile);
             OutputStream outputStream = new FileOutputStream(destFile)) {
            while (true) {
                byte[] buffer = new byte[20480];
                int n = inputStream.read(buffer);
                System.out.println("n = " + n);
                if (n == -1) {
                    System.out.println("读取到 eof,即读取到末尾了,循环结束! ");
                    break;
                }
                outputStream.write(buffer, 0, n);
            }
        }
    }
}

(3)题目三

💓题目:扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Demo12 {
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        // 接收用户输入的路径
        System.out.println("请输入要扫描的路径:");
        String rootPath = scanner.next();
        // 校验路径合法性
        if (rootPath == null || rootPath.equals("")) {
            System.out.println("路径不能为空。");
            return;
        }
        //实例化为File对象
        File rootDir = new File(rootPath);
        //判断rootDir的真实性
        if (rootDir.exists() == false) {
            System.out.println("指定的目录不存在,请检查。");
            return;
        }
        if (rootDir.isDirectory() == false) {
            System.out.println("指定的路径不是一个目录。请检查。");
            return;
        }

        // 接收要查找的关键字
        System.out.println("请输入要查找的关键字:");
        String key = scanner.next();
        if (key == null || key.equals("")) {
            System.out.println("查找的关键字不能为空,请检查。");
            return;
        }

        // 遍历目录查找符合条件的文件
        // 保存找到的文件
        List<File> fileList = new ArrayList<>();
        scanDir(rootDir, key, fileList);

        // 打印结果
        if (fileList.size() > 0) {
            System.out.println("共找到了 " + fileList.size() + "个文件:");
            for (File file: fileList) {
                System.out.println(file.getAbsoluteFile());
            }
        } else {
            System.out.println("没有找到相应的文件。");
        }

    }

    private static void scanDir(File rootDir, String token, List<File> fileList) throws IOException {
        // 获取目录下的所有文件并放入files数组中
        File[] files = rootDir.listFiles();
        if (files == null || files.length == 0) {
            return;
        }

        // 遍历
        for (File file : files) {
            if (file.isDirectory()) {
                // 如果是目录文件就递归
                scanDir(file, token, fileList);
            } else {
                //  如果是普通文件就判断
                //  文件名是否包含关键词
                if (file.getName().contains(token)) {
                    fileList.add(file);
                } else {
                    if (isContainContent(file, token)) {
                        fileList.add(file.getAbsoluteFile());
                    }
                }
            }
        }
    }

    private static boolean isContainContent(File file, String token) throws IOException {
        // 定义一个StringBuffer存储读取到的内容
        StringBuffer sb = new StringBuffer();
        // 输入流
        try (InputStream inputStream = new FileInputStream(file)) {
            try (Scanner scanner = new Scanner(inputStream, "UTF-8")) {
                // 读取每一行
                while (scanner.hasNext()) {
                    // 一次读一行
                    sb.append(scanner.nextLine());
                    // 加入一行的结束符  (String对象写入到文件时,换行符应该把\n写完整成\r\n)
                    sb.append("\r\n");
                }
            }
        }
        return sb.indexOf(token) != -1;   //sb.indexOf(token)找不到就会返回-1  (-1!= -1 返回false,反之返回true)
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值