JavaEE & 文件操作和IO & 目录扫描全文检索小程序

不知道说啥了,看看吧在这里插入图片描述

文章目录

  • JavaEE & 文件操作和IO
    • 1. 文件系统操作
      • 1.1 路径
      • 1.2 文本文件 与 二进制文件
      • 1.3 文件系统操作
        • 1.3.1 构造File对象
        • 1.3.2 使用File对象
    • 2. 文件内容操作
      • 2.1 获取文件输入流InputStream(字节流)
        • 2.1.1 read方法
        • 2.1.2 不带参数的read方法
        • 2.1.3 给定数组的read方法
      • 2.2 获取文件输出流OutputStream(字节流)
        • 2.2.1 write方法
        • 2.2.2 write 传入单个字节的构造方法
        • 2.2.3 write 传入字节数组的构造方法
      • 2.3 字符流 Reader 与 Writer
        • 2.3.1 Reader的读方法
        • 2.3.2 Writer的写操作
    • 3. 小程序练习:全文检索
      • 3.1 控制台输入根目录与关键字
      • 3.2 scan递归方法
      • 3.3 readAll读取文件方法
      • 3.4 测试

JavaEE & 文件操作和IO

在之前的学习中,基本上都是围绕内存展开的~

  • MySQL 主要是操作硬盘的

  • 文件IO也是是操作硬盘的~

IOinput output

1. 文件系统操作

  • 创造文件,删除文件,重命名文件,创建目录······
  • 一些操作没有权限也做不了~

1.1 路径

  • 就是我们的文件系统上的一个文件/目录的具体位置
    • 目录:文件夹
  • 计算机的目录是有层级结果的,即N叉树

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第1张图片

  • 我的代码库目录:

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第2张图片

  • 那么这篇文章的源码所在的目录具体位置是什么呢?

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第3张图片

  • 所以,路径就是:D:/马库/marathon-april-2023/文件IO
    • 这是个绝对路径
      1. 绝对路径,即从盘符开始到具体文件/目录
      2. 相对路径,从指定目录开始到具体文件/目录
        • 要确认**(基准)工作目录**是什么~

而里面的src目录下有java文件,out目录里面就有class文件,同样有对应的路径

  1. / 分割,推荐!
  2. \ 分割的话要加转义字符\ , 即 \\
    • 一般只能适用于Windows
  3. …/ 代表这一级的上一个目录
  4. . 代表这当前目录(与后续目录要以 / 分割,即 . / )通常可以省略
  5. . . 代表当前目录的上一级目录(与后续目录要以 / 分割,即 . . /
    • . . / . . / 代表上一级目录的上一级目录~
  6. 默认源头的源头是“此电脑”目录,可以不写

绝对路径可以认为是以“此电脑”为工作目录的相对路径

  • 并且任何一个文件/目录,对应的路径,肯定是唯一的

    • 在LInux可能出现两个不同路径找到同一文件的情况~
    • 但是在Windows上不存在~
  • 路径与文件一一对应~

  • 路径为文件的身份

1.2 文本文件 与 二进制文件

  • 这个就是字面意思了

文本文件:

  • 存储字符(不仅仅是char类型)

二进制文件:

  • 存储什么都OK,因为任何数据都是以二进制为根本的

判断:

  • 记事本打开,是文本就是文本,是二进制就是二进制~
  1. .txt文件:文本 / 二进制,看你怎么创造的~

  2. .java / .c 文件文本文件

    • 拖动到记事本里
      JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第4张图片
  3. .class / .exe 文件二进制文件~

  1. .jpg / mp3 二进制文件
    • 乱码,即把这一个个字节转化为字符型,而原本不是字符型的~

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第5张图片

  1. pdf xlsx doc … : 二进制文件

  • csv excel的文本格式:

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第6张图片

1.3 文件系统操作

  • Java标准库提供了一个类:File
    • File对象代表着一个文件,是那个文件的抽象表示~
  • 硬盘上的文件 ==> 内存中的File对象 ==> 在内存上改变硬盘上的一些东西

1.3.1 构造File对象

  • 需要传一个文件路径为参数~
    • 这个文件可以存在也可以不存在

例如这张图片~

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第7张图片

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第8张图片

1.3.2 使用File对象

  • 不手动常见文件是不会自动创建的
    • 不会再new的时候创建
序号 方法名 方法说明
1 String getParent() 返回 File 对象的父目录文件路径
2 String getName() 返回 FIle 对象的纯文件名称
3 String getPath() 返回 File 对象的文件路径
4 String getAbsolutePath() 返回 File 对象的绝对路径
5 String getCanonicalPath() 返回 File 对象的修饰过的绝对路径
6 boolean exists() 判断 File 对象描述的文件是否真实存在
7 boolean isDirectory() 判断 File 对象代表的文件是否是一个目录
8 boolean isFile() 判断 File 对象代表的文件是否是一个普通文件
9 boolean createNewFile() 根据 File 对象,自动创建一个空文件。成功创建后返 回 true
10 boolean delete() 根据 File 对象,删除该文件。成功删除后返回 true
11 void deleteOnExit() 根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行
12 String[] list() 返回 File 对象代表的目录下的所有文件名
13 File[] listFiles() 返回 File 对象代表的目录下的所有文件,以 File 对象表示
14 boolean mkdir() 创建 File 对象代表的目录
15 boolean mkdirs() 创建 File 对象代表的目录,如果必要,会创建中间目录
16 boolean renameTo(File dest) 进行文件改名,也可以视为我们平时的剪切、粘贴操作
17 boolean canRead() 判断用户是否对文件有可读权限
18 boolean canWrite() 判断用户是否对文件有可写权限

小小演示:

  1. 绝对路径
public static void main(String[] args) throws IOException {
    File file = new File("d:/马图/瞪眼.jpg");
    System.out.println(file.getParent());
    System.out.println(file.getName());
    System.out.println(file.getPath());
    System.out.println(file.getAbsoluteFile());
    System.out.println(file.getCanonicalFile());
}
  • IOException是IO操作的会抛出的常见异常
    • 是首查异常,也叫编译时异常

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第9张图片

  1. 相对路径
    • 默认是与src目录的上一级的为工作目录~
    • 就是项目所在目录
    • 而不是src这一级

  • 打印得出来这个文件不代表就存在这个文件~
  1. 是否存在?

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第10张图片

  1. 性质,创造文件,删除文件
    • 是存在既不是目录又不是普通文件的文件的
    • 例如socket文件等等~
public static void main(String[] args) {
    File file = new File("./helloWorld.txt");
    System.out.println(file.exists());
    System.out.println(file.isDirectory());//是目录吗?(文件夹)
    System.out.println(file.isFile());//是文件吗?(普通文件)
}

  1. 创建与删除目录
public static void main(String[] args) {
    File file = new File("./helloWorld");
    if(!file.exists()) {
        file.mkdir();
    }
    System.out.println(file.exists());
    System.out.println(file.isFile());
    System.out.println(file.isDirectory());
}

make directory

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第11张图片

  1. 路径转化为数组

获取目录里的所有文件/目录

  • list ==> 文件 /目录名数组
  • listFile ==> File对象 数组
public static void main(String[] args) {
    File file = new File("helloWorld");
    String[] results1 = file.list();
    File[] results2 = file.listFiles();
    System.out.println(Arrays.toString(results1));
    System.out.println(Arrays.toString(results2));
}

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第12张图片

  1. 重命名
public static void main(String[] args) {
    File file = new File("helloWorld");
    file.renameTo(new File("HELLO_WORLD"));
}

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第13张图片

2. 文件内容操作

  • 针对文件内容进行 读 与 写

  • 文件操作依赖于一些类,或者说是多组类

    1. 文本 ==> ”字符流“
    2. 二进制 ==> “字节流”

“流”:

  • 数据的运输像河流一样,流向哪,从哪流来~

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第14张图片

2.1 获取文件输入流InputStream(字节流)

public static void main(String[] args) throws IOException {
    InputStream inputStream = new FileInputStream("HELLO_WORLD");
		
    //coding

    inputStream.close();

}

有了输入流,就相当于你有了“介质”

  • 相当于打开文件,文件的信息可以出来

关闭输入流

  • 相当于关闭文件
  • 如果不关闭,可能会导致,文件资源泄露 ===>
  • 进程里有个文件描述符表,一旦打开文件多了,这个表可能会爆了,导致机器出问题!
  • Java的对象,没用了会自动释放,但是这里的流对象并不会!!!

正确的写法:(利用finally保证关闭能够进行)

  • try括号内为打开文件操作,默认finally关闭文件~
    • try with resources操作
public static void main(String[] args) {
    try(InputStream inputStream = new FileInputStream("HELLO_WORLD/123.txt")) {

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • InputStream实现Closeable接口,那么就可以这样操作~
    • 这就是try with resource操作的要求
    • 注意:后续内容都是以这种方式打开与隐式关闭文件的
      在这里插入图片描述

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第15张图片

2.1.1 read方法

  • 只能说文件里有个指针指着读在哪了,并不是读了后原文件就删了~
方法名 方法说明
int read() 一次读一个字节并返回,返回-1代表读完了
int read(byte[] b) 填满此数组为止,返回-1表示读完(可能填不满)
int read(byte[] b, int off, int len) 填满此数组的[off, off + len)为止,返回-1表示读完(可能填不满)
  • 在java对此方法的描述中提到:返回的字节转化为int类型,范围是0 - 255

手写一些数据:

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第16张图片

2.1.2 不带参数的read方法

public static void main(String[] args) {
    try(InputStream inputStream = new FileInputStream("HELLO_WORLD/123.txt")) {
        int b = 0;
        do {
            b = inputStream.read();
            System.out.println(b);
        }while(b != -1);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 测速结果:

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第17张图片

  • 对于中文:

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第18张图片

  • 测试结果:
    • 不是说一个中文 ==> 一个char字符 两个字节吗,为什么这里是三个字节一个汉字
    • 那是因为Unicode每个字符是两个字节
    • UTF-8汉字是三个字节,其他字符一个字节~
      • 我编译器无脑全设置UTF-8了
    • 而读取的内容可没有规定就是Java的char类型呀~
      • 但是我们可以通过一些手段翻译这个东西,后面讲~

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第19张图片

  • 字符对应表 - 查询网站:查看字符编码(UTF-8) (mytju.com)

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第20张图片

E9 : 233 A9 : 169 AC : 172 ················

完美对应~

2.1.3 给定数组的read方法

public static void main(String[] args) {
    try(InputStream inputStream = new FileInputStream("HELLO_WORLD/123.txt")) {
        byte[] bytes = new byte[9];
        System.out.println(inputStream.read(bytes));
        System.out.println(Arrays.toString(bytes));


    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 测试结果:

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第21张图片

  • 咋变负数了?

    • 因为读取到的字节仍然是 -128 - 127 的
    • 只不过刚才返回int类型的是无符号的~
  • 如何翻译呢?

    • 用String的构造方法~

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第22张图片

2.2 获取文件输出流OutputStream(字节流)

public static void main(String[] args) {
    //每次打开输出流,都会清空文件内容~
    try(OutputStream outputStream = new FileOutputStream("HELLO_WORLD/123.txt")) {
        

    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 每次打开文件,会清空原内容!
    JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第23张图片

2.2.1 write方法

方法名 方法说明
void write(int b) 传入一个int型,内部强行转化为byte型
void write(byte[] b) 将整个字节数组写入文件中
int write(byte[] b, int off, int len) 将字节数组的[off, off + len)部分写入文件中
void flush() 重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为 了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的 一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写 入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的 数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置, 调用 flush(刷新)操作,将数据刷到设备中。
  • flush很重要,在关闭之前没有flush,文件内容就无法得以更新

2.2.2 write 传入单个字节的构造方法

public static void main(String[] args) {
    //每次打开输出流,都会清空文件内容~
    try(OutputStream outputStream = new FileOutputStream("HELLO_WORLD/123.txt")) {

        outputStream.write(1);
        outputStream.write(2);
        outputStream.write(3);
        outputStream.write(4);
        outputStream.flush();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第24张图片

2.2.3 write 传入字节数组的构造方法

public static void main(String[] args) {
    //每次打开输出流,都会清空文件内容~
    try(OutputStream outputStream = new FileOutputStream("HELLO_WORLD/123.txt")) {

        outputStream.write(new byte[]{1, 2, 3, 4, 5, 6, 7});
        outputStream.flush();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第25张图片

2.3 字符流 Reader 与 Writer

2.3.1 Reader的读方法

  • 对比于字节流,这里读的是字符,读进字符数组~
    public static void main(String[] args) throws FileNotFoundException {
        try(Reader reader = new FileReader("HELLO_WORLD/123.txt")) {
            char ch = (char)reader.read();
            char[] chars = new char[7];
            reader.read(chars);
            System.out.println(ch);
            System.out.println(chars);
            int c = 0;
            do {
                c = reader.read();
                System.out.println((char)c);
            }while (c != -1);
        } catch (IOException e) {
            e.printStackTrace();
        }

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第26张图片

  • 测试结果:
    • 同样read返回-1,代表读完了~

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第27张图片

2.3.2 Writer的写操作

  • 对比于字节流,这里写入的是字符,字符数组,或者字符串~

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第28张图片

    public static void main(String[] args) {
        try(Writer writer = new FileWriter("HELLO_WORLD/123.txt")) {
            writer.write('0');
            writer.write(new char[]{'1', '2', '3', '4', '5', '6'});
            writer.write("789");
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 写操作跟字节流一样,无此文件,自动创建~

  • 并且还会清空原内容

  • 测试结果:

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第29张图片

3. 小程序练习:全文检索

  • 就是遍历目录,并在文件内容中查找信息

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第30张图片

接下来以简单粗暴的方式去实现~

3.1 控制台输入根目录与关键字

public static void main(String[] args) throws IOException {
    Scanner scanner = new Scanner(System.in);
    System.out.print("请输入要扫描的根目录:");
    String root = scanner.next();
    File file = new File(root);
    if(!file.isDirectory()) { // 1. 目录不存在 2. 不是目录
        System.out.println("输入错误");
        return;
    }
    System.out.print("请输入要查询的词:>");
    String words = scanner.next();
    scan(file, words);//扫描
}
  1. 根据根目录构造File对象
  2. 如果这个file对象不是目录或者不存在的话,则说明输入错误,直接返回退出程序
  3. 如果是目录,输入要关键字
  4. 调用scan方法对目录进行扫描(自己实现)

3.2 scan递归方法

  • n叉树就得写循环来递归了
  • 如果是扫描到二进制文件,我们也不指望里面有我们要的文本,因为二进制一般存放一些后端数据信息,并不是给人看的,不是观赏性的,但是二进制文件还是可能会读到的~
  • 记得设立递归出口,死递归会导致栈溢出
public static void scan(File file, String words) throws IOException {
    File[] files = file.listFiles();
    if(files == null) { 
        // 这里空目录对应的并不是空数组!是null~
        return;
    }else {
        for (int i = 0; i < files.length; i++) {
            File f = files[i];
            if(f.isFile()) {
                String content = readAll(f);
                if(content.contains(words)) {
                    System.out.println(f.getCanonicalFile());
                }
            }
            if(f.isDirectory()) {
                scan(f, words);
            }
            //两种都不是的其他文件,就不能读~
        }
    }

}

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第31张图片

3.3 readAll读取文件方法

  • 利用StringBuilder拼接字符串~
    • 用Reader字符流读取数据~
    • 对于Java,这些流对象只是读取方式,对文件是二进制还是文本没有要求
  • 最终返回
public static String readAll(File f) {
    StringBuilder stringBuilder = new StringBuilder();
    try (Reader reader = new FileReader(f)){
        while(true) {
            int c = reader.read();
            if(c == -1) {
                break;
            }
            stringBuilder.append((char)c);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return stringBuilder.toString();
}

在这里插入图片描述

  • 堆溢出~

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第32张图片

3.4 测试

  • 测试用例:
    • 如果文件数量多,内容多,以此法会卡的半死
    • 到时候我们学习一下“倒排索引”这种数据结构,可能能够很好地优化!

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第33张图片

  1. 根目录是:d:/马库/marathon-april-2023
  2. 关键字是:马大帅
  • 测试结果:

JavaEE & 文件操作和IO & 目录扫描全文检索小程序_第34张图片

  • 测试结果正常!
    • 另外两个可能是其他项目里提到了这个关键字 ^ V ^

文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭

文件操作的讲解告一段落,后面也会涉及到哦!

实践才是最好的学习!


你可能感兴趣的:(JavaEE,java-ee,java,文件,全文检索)