文章目录
- File 类
- OutputStream、InputStream
- InputStream
- OutputStream
- Reader、Writer
- Reader
- Writer
- 注意事项
- 简单模拟实战
File 类
Java标准库中提供的File
类是对硬盘上的文件的抽象,每一个File
对象代表了一个文件,因为文件在硬盘上存储,而直接操作硬盘太过麻烦,所以我们就在内存中抽象一个文件对象,通过改变这个对象间接改变硬盘上的文件。
在构造对象时我们可以使用绝对路径或者相对路径,构造的文件对象可以真实存在也可以不存在,标准库中也为我们提供了很多的方法:
返回值类型 | 方法名 | 说明 |
---|---|---|
String | getParent() | 返回 File 对象的父目录文件路径 |
String | getName() | 返回 FIle 对象的纯文件名称 |
String | getPath() | 返回 File 对象的文件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 |
boolean | exists() | 判断 File 对象描述的文件是否真实存在 |
boolean | isDirectory() | 判断 File 对象代表的文件是否是一个目录 |
boolean | isFile() | 判断 File 对象代表的文件是否是一个普通文件 |
boolean | createNewFile() | 根据 File 对象,自动创建一个空文件。成功创建后返回 true |
boolean | delete() | 根据 File 对象,删除该文件。成功删除后返回 true |
void | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会行 |
String[] | list() | 返回 File 对象代表的目录下的所有文件名 |
File[] | listFiles() | 返回 File 对象代表的目录下的所有文件,以 File 对象表示 |
boolean | mkdir() | 创建 File 对象代表的目录 |
boolean | mkdirs() | 创建 File 对象代表的目录,如果必要,会创建中间目录 |
boolean | renameTo(Filedest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操作 |
boolean | canRead() | 判断用户是否对文件有可读权限 |
boolean | canWrite() | 判断用户是否对文件有可写权限 |
下面我们来简单的示范使用一下:
此时我们创建File对象使用的是相对路径,此时项目所在的目录就是工作目录,我们通过调用一些方法获取到了文件的相关信息。
此时我们使用一个不存在的文件去创建File对象,同样可以成功,因为创建File对象是不要求文件一定存在,此时我们通过方法去判断File对象是否是一个文件或者目录,肯定返回的是false
,我们可以调用createNewFile()
去创建该文件,创建后再次进行判断。
使用mkdir()
可以创建目录,想要创建多级目录使用mkdirs()
。
list
可以返回File对象下的所有文件名,listFiles
返回时包含自己,此时根据上图我们创建的多级目录可以看出,test目录下的文件只有一个aa。
以上就是Java中File类的简单介绍。
OutputStream、InputStream
我们可以创建文件删除文件之后,是不是要向文件当中写入一些东西,或者从文件中读取一些东西。此时Java也为我们提供很对类:
针对文本文件,可以使用:
Reader Writer
去读和写,他们读写的基本单位是字符,称为字符流。
针对二进制文件,可以使用
InputStream OutputStream
,他们读写的基本单位是字节,称为字节流。
我们有了一个新的概念叫做流,这该怎么理解呢?
InputStream
返回值类型 | 项目 | Value |
---|---|---|
int | read() | 读取一个字节的数据,返回 -1 代表已经完全读完了 |
int | read(byte[] b) | 最多读取 b.length 字节的数据到 b 中,返回实际读到的数量;-1 代表以及读完了 |
int | read(byte[] b,int off, int len) | 最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表已经读完了 |
void | close() | 关闭字节流 |
此时我们创建一个txt文件,通过InputStream
对象去读取这个文件里面的内容:
OutputStream
返回值类型 | 项目 | Value |
---|---|---|
void | write(int b) | 写入要给字节的数据 |
void | write(byte[]b) | 将 b 这个字符数组中的数据全部写入 os 中 |
int | write(byte[]b, int off,int len) | 将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个 |
void | close() | 关闭字节流 |
void | flush() | 重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。 |
我们通过OutputStream
向刚才创建的txt文件中写入一些数据:
此时我们发现,文件中的内容从abc变为了我们输入的内容
Reader、Writer
Reader
Writer
同样使用Writer
对象向txt文件中写入一些数据。
注意事项
1、上述的类
OutputStream、InputStream
都是抽象类,实现的时候需要使用具体的类,他们的实现类有很多,目前我们只关心从文件中读写,所以使用FileInputStream。Reader、Writer
也是一样,都是抽象类,实现需要具体的类。
2、每次使用完必须要使用
close()
进行关闭,在一个进程中,当我们打开一个文件就会有一个文件描述符记录我们打开了哪些文件,这些文件描述符多了之后会生成一个文件描述符表,每次打开会在这个表中申请一个位置,但是这个表的大小是有限制的,如果不进行关闭释放,表满了再打开文件就会失败。
有的兄弟会说了,上述代码你一个close()
也没有啊!!!正常来说我们打开文件和关闭文件可以这样写:
但是这样会导致如果代码很复杂有可能close()
方法执行不到,我们进行优化:
这样写可以保证close()
方法一定被执行到,但是这样写不够优雅,我们再次优化,Java给我们提供了一个语法叫做try with resources
:
因为InputStream
实现了一个特定的接口Closeable
,所以带有资源的try
操作,会在try
代码块结束,自动执行close
操作。
简单模拟实战
需求:扫描指定目录,找到包含相关内容的的普通文件
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Scanner;
public class IOTestMyself {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入你要查找的目录:");
File rootDir = new File(scanner.next());
if (!rootDir.isDirectory()) {
System.out.println("您输入的目录不存在,请重新输入");
}else {
System.out.println("请输入你要查找的内容:");
String word = scanner.next();
scanDir(rootDir,word);
break;
}
}
}
private static void scanDir(File rootDir,String word) {
File[] files = rootDir.listFiles();
if(files == null) {
return;
}
for (File f: files) {
System.out.println("当前查找目录" + f.getAbsolutePath());//打印一下日志
if(f.isFile()) {
//是文件就查找
String ret = readFile(f);
if(ret.contains(word)) {
System.out.println(f.getAbsolutePath() + "包含查找内容");
}
}else if(f.isDirectory()) {
//是目录递归查找下级目录
scanDir(f,word);
}else {
//啥也不是跳过
continue;
}
}
}
private static String readFile(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 (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
}