当前位置:首页 » 《随便一记》 » 正文

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

13 人参与  2023年05月04日 12:02  分类 : 《随便一记》  评论

点击全文阅读


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

在这里插入图片描述

文章目录

JavaEE & 文件操作和IO1. 文件系统操作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 与 Writer2.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叉树

在这里插入图片描述

我的代码库目录:

在这里插入图片描述

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

在这里插入图片描述

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

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

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

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

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

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

路径与文件一一对应~

路径为文件的身份

1.2 文本文件 与 二进制文件

这个就是字面意思了

文本文件:

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

二进制文件:

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

判断:

记事本打开,是文本就是文本,是二进制就是二进制~

.txt文件:文本 / 二进制,看你怎么创造的~
在这里插入图片描述

.java / .c 文件文本文件

拖动到记事本里
在这里插入图片描述

.class / .exe 文件二进制文件~

在这里插入图片描述

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

在这里插入图片描述

pdf xlsx doc … : 二进制文件

在这里插入图片描述

csv excel的文本格式:

在这里插入图片描述

1.3 文件系统操作

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

1.3.1 构造File对象

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

例如这张图片~

在这里插入图片描述

在这里插入图片描述

1.3.2 使用File对象

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

小小演示:

绝对路径
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操作的会抛出的常见异常 是首查异常,也叫编译时异常

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

性质,创造文件,删除文件 是存在既不是目录又不是普通文件的文件的例如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());//是文件吗?(普通文件)}

在这里插入图片描述

创建与删除目录
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

在这里插入图片描述

路径转化为数组

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

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));}

在这里插入图片描述

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

在这里插入图片描述

2. 文件内容操作

针对文件内容进行 读 与 写

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

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

“流”:

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

img

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操作的要求注意:后续内容都是以这种方式打开与隐式关闭文件的
在这里插入图片描述

在这里插入图片描述

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

手写一些数据:

在这里插入图片描述

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();    }}
测速结果:

在这里插入图片描述

对于中文:

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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();    }}
测试结果:

在这里插入图片描述

咋变负数了?

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

如何翻译呢?

用String的构造方法~

在这里插入图片描述

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

public static void main(String[] args) {    //每次打开输出流,都会清空文件内容~    try(OutputStream outputStream = new FileOutputStream("HELLO_WORLD/123.txt")) {            } catch (IOException e) {        e.printStackTrace();    }}
每次打开文件,会清空原内容!
在这里插入图片描述

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();    }}

在这里插入图片描述

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();    }}

在这里插入图片描述

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();        }

在这里插入图片描述

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

在这里插入图片描述

2.3.2 Writer的写操作

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

在这里插入图片描述

    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();        }    }

写操作跟字节流一样,无此文件,自动创建~

并且还会清空原内容

测试结果:

在这里插入图片描述

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

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

在这里插入图片描述

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

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);//扫描}
根据根目录构造File对象如果这个file对象不是目录或者不存在的话,则说明输入错误,直接返回退出程序如果是目录,输入要关键字调用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);            }            //两种都不是的其他文件,就不能读~        }    }}

在这里插入图片描述

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();}

在这里插入图片描述

堆溢出~

在这里插入图片描述

3.4 测试

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

在这里插入图片描述

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

在这里插入图片描述

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

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

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

实践才是最好的学习!



点击全文阅读


本文链接:http://zhangshiyu.com/post/60636.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1