文件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 一次返回一个字节,但是此处的返回值类型是 int
while (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中,统一转换成 String
while (true) {
int c = reader.read();
if (c == -1) {
{
break;
}
}
builder.append((char)c);
}
} catch (IOException e) {
e.printStackTrace();
}
return builder.toString();
}
}