一文带你迅速掌握【文件操作】
文件IO操作—>操作硬盘
- 1.文件系统操作:创建文件、删除操作、重命名文件、创建目录…
- 2.文件内容操作:针对文件内容进行 读 和 写
1. 文件系统操作
Java 标准库,提供了一个 File 这个类
- 构造一个 File对象,构造过程中,可以使用 绝对路径/相对路径 进行初始化,这个路径指向的文件,可以是真实的,也可以是不存在~
File file = new File("test-dir/aaa/bbb");
- File 提供来了一些方法
2. 文件内容操作
- 针对文本文件,提供了一组类,统称为 “字符流”(典型代表,Reader,Writer)
- 针对二进制文件,提供了一组类,统称为 “字节流” (典型代表,InputStream , OutputStream)
每种流对象,又分为两种
- 输入的:Reader、InputStream
- 输出的:Writer、OutputStrem
2.1 InputStream
通过源码可以看到 InputStream 是一个抽象类,是不能直接创建实例的,可以创建它的子类实例 FileInputStream
但是这里有一个重点:一定要记得 close,文件资源需要手动释放
这里的文件资源指的是 “文件描述符”
进程,是使用PCB这样的结构来表示的
1.pid
2.内存指针
3.文件描述符表
文件描述符表:就是记录了当前进程都打开了哪些文件,每次打开一个文件,就会在这个表里,申请到一个元素。这个表可以当成 一个数组,数组下标就是描述符,数组中的元素,就是这个文件在内核中的结构体的表示
由于,这个表长度有限制的,不能无休止的打开,但是又不释放,一旦满了,继续打开,就会打开失败~ 造成文件资源泄露
我们将代码写成如下,就不需要手动再写 close, 带有资源的 try 操作,会在 try 代码块结束后,自动执行 close 关闭操作 (是因为 InputStream 实现了 Closeable 接口)
public class IODemo3 {public static void main(String[] args) throws IOException {try (InputStream inputStream = new FileInputStream("f:/test.txt")) {// 读文件操作// read 一次返回一个字节,但是此处的返回值类型是 intwhile (true){int b = inputStream.read();if (b == -1){// 读到末尾break;}System.out.println(b);}}}
}
2.2 利用 Scanner 进行字符读取
public class IODemo4 {public static void main(String[] args) throws IOException {try (InputStream inputStream = new FileInputStream("f:/test.txt")) {try(Scanner scanner = new Scanner(inputStream,"UTF-8")){while (scanner.hasNext()){String s = scanner.nextLine();System.out.println(s);}}}}
}
2.3 outputStream
public class IODemo5 {public static void main(String[] args) {try(OutputStream outputStream = new FileOutputStream("f:/test.txt")){outputStream.write(97);outputStream.write(97);outputStream.write(97);} catch (IOException e) {throw new RuntimeException(e);}}
}
2.4 Reader
public class IODemo6 {public static void main(String[] args) {try(Reader reader = new FileReader("f:/test.txt")){while (true){int c = reader.read();if (c == -1){break;}System.out.println((char)c);}} catch (IOException e) {throw new RuntimeException(e);}}
}
3. 案例
遍历目录,在里面的文件内容中查找 包含 xxxx 信息的文件
采用简单粗暴的递归方式:
-
- 先去递归的遍历目录,比如给定一个 f:/ 去递归的把所有的文件都列出来
-
- 每次找到一个文件,都打开,并读取文件内容(得到String)
-
- 再判定要查询的词,是否在上述文件内容中存在,如果存在,就是要找的文件,打印出文件位置
package io;import java.io.*;
import java.util.Scanner;public class IODemo7 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 1. 先让用户指定一个要搜索的目录System.out.println("请输入要扫描的根目录");File rootDir = new File(scanner.next());if (!rootDir.isDirectory()) {System.out.println("输入有误,您输入目录不存在");return;}// 2. 用户输入查询的词System.out.println("请输入要查询的词:");String word = scanner.next();//3. 递归的进行目录/文件的遍历scanDir(rootDir, word);}private static void scanDir(File rootDir, String word) {// 列出当前的 rootDir中的内容,没有内容,直接递归结束File[] files = rootDir.listFiles();if (files == null) {return;}// 目录有内容,遍历目录中的每个元素for (File f : files) {if (f.isFile()) {// 是普通文件String content = readFile(f);if (content.contains(word)) {System.out.println(f.getAbsoluteFile() + "包含要查找的关键字");}} else if (f.isDirectory()) {// 是目录scanDir(f,word);} else {// 不是普通文件,也不是目录文件,直接跳过continue;}}}private static String readFile(File f) {// 读取文件的整个内容,返回出来// 使用字符流来读取,由于咱们匹配的是字符串,此处只能按照字符流,才有意义StringBuilder builder = new StringBuilder();try (Reader reader = new FileReader(f)) {// 一次读一个字符,把读到的结果拼装到 StringBuilder中,统一转换成 Stringwhile (true) {int c = reader.read();if (c == -1) {{break;}}builder.append((char)c);}} catch (IOException e) {e.printStackTrace();}return builder.toString();}
}