前言
学习的思维导图
目录
1. File类是什么?
2. 关于文件系统的操作
3. 关于文件内容的操作
3.1 文本文件
3.2 二进制文件
4. 案例实现练习
5.拓展:try with resources 操作
1. File类是什么?
● 概念
它的实例化对象是对硬盘上文件或目录的抽象表示.文件存储在硬盘上,我们如果直接去操作会很不方便,所以我们可以在内存中创建对应对象,然后通过操作该对象去间接影响硬盘上的文件.在java语言中,我们可以通过如下方式抽象化表示某个路径下的某个文件.它的父类和实现接口如下:
● 示例代码
System.out.println("请输入要扫描的指定目录:>");
Scanner s = new Scanner(System.in); //可以是当前项目下的相对路径,也可以是绝对路径
String dir = s.nextLine();
File file = new File(dir);
2. 关于文件系统的操作
这里不介绍所有操作,只介绍常用操作,大家先看这个图:
① 这是我本地用于测试的目录:
② 具体练习代码:
public class FileTest2 {
public static void main(String[] args) throws IOException {
File f = new File("E:\\比特就业课\\Java\\io测试目录");
System.out.println(f.getParent());
System.out.println(f.getName());
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
System.out.println(f.exists());
System.out.println(f.isDirectory());
System.out.println(f.isFile());
//原地创建一个由该抽象路径名命名的新的空文件
//如果命名文件已经存在返回false,不存在创建新文件并返回true
System.out.println(f.createNewFile());
File f2 = new File("E:\\比特就业课\\Java\\io测试目录\\test222.txt");
System.out.println(f2.delete());
File testF = new File("E:\\测试单个目录创建");
System.out.println(testF.mkdir());
File testF2 = new File("E:\\测试多个目录创建\\direct1\\direct2");
System.out.println(testF2.mkdirs());
String[] content = f.list();
assert content != null;
for (String item:content) {
System.out.print(item + " ");
}
System.out.println();
File[] content2 = f.listFiles();
assert content2 != null;
for (File item:content2) {
System.out.print(item.getName() + " ");
}
System.out.println();
System.out.println(f.renameTo(testF));
}
}
③ 执行结果:
注:当前测试目录并不在项目路径底下.
3. 关于文件内容的操作
3.1 文本文件
文本文件是基于字符编码的文件,常见的编码有ASCII编码,Unicode编码等等.这里先给大家引入一个"流"的概念,可以将它想象成水管,流中流动的不是水,而是字节序列.从流中读取一个字节序列的对象称为输入流,向流中写入一个字节序列的对象称为输出流.而流又可以分为两类,一个是字节流(处理基本单位是字节),另一个是字符流(处理基本单位是字符).
我们通常使用字符流来处理文本数据,Java中对应的字符流基本抽象类为Reader和Writer,它们的直接子类是InputStreamReader,OutputStreamWriter.但是一般我们实例化的是它们的间接子类:
FileReader和FileWriter.下面我们来练习一下文本文件的读取和写入吧~测试文本文件内容如下:
● 示例代码
File f = new File("E:\\某个目录\\Java\\io测试目录\\test222.txt");
//读数据
try (Reader reader = new FileReader(f)){
StringBuilder stringBuilder = new StringBuilder();
while (true) {
int ret = reader.read();
if (ret == -1) break; //文件读取到末尾
stringBuilder.append((char) ret);
}
System.out.println(stringBuilder.toString());
} catch (IOException e) {
e.printStackTrace();
}
//写数据
try (Writer writer = new FileWriter(f)){
StringBuilder stringBuilder = new StringBuilder("早安,全世界");
writer.write(stringBuilder.toString()); //也可以一个字符一个字符的写
} catch (IOException e) {
e.printStackTrace();
}
● 执行结果
注:不同的编码格式,一个字符所占的字节大小不一样.
3.2 二进制文件
二进制文件是基于值编码的文件,没有字符集限制,什么都能存.
我们通常使用字节流来处理二进制数据,Java中对应的字符流基本抽象类为InputStream和OutputStream,它们的直接子类是FileInputStream,FileOutputStream.因为二进制文件我们是难以看懂的,为了方便我们看懂,下面我们使用字节流来处理一下文本文件内容分析一下,测试文本文件内容如下:
● 示例代码
File f = new File("E:\\比特就业课\\Java\\io测试目录\\test222.txt");
//读数据(二进制)
try (InputStream inputStream = new FileInputStream(f)){
while (true) {
int ret = inputStream.read();
if (ret == -1) break;
System.out.print((char)ret + " "); //得到的字符集十进制值转换成字符
}
} catch (IOException e) {
e.printStackTrace();
}
//写数据(二进制)
try (OutputStream outputStream = new FileOutputStream(f)){
byte[] data = new byte[1024];
byte b = 65;
for (int i = 0; i < 26; i++) {
data[i] = b;
b++;
}
outputStream.write(data);
} catch (IOException e) {
e.printStackTrace();
}
● 执行结果
大家可能就有疑问了,我的文本内容明明是HELLO WORLD为什么读出来是这些数字,认真看这些数字,大家会发现这些是对应字符的ASCII码值,因为字节流处理的基本单位是字节.如果文本内容是中文,那么就会根据对应的字符集编码,得到一个汉字多少个字节,假设一个汉字是2个字节,那么输出的就是对应字符编码的十进制数值.
我们将得到的结果转成字符型,那么得到的就是我们想要的效果了(写也是类似):
此时文本文件中显示的对应ASCII的字符.
注:文件的打开,使用完毕后,一定要进行关闭,不然会导致文件资源一直被占用.
4. 案例实现练习
扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录).
● 具体思路:
① 得到给定的目录及所需查找的内容.
② 递归遍历给定目录的子目录.
③ 得到子目录下的所有内容,如果是文件就获取它的内容,目录就继续递归遍历.其它类型的内容我们暂时不做考虑.
● 实现代码:
public class FileTest {
public static void main(String[] args) {
//扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
System.out.println("请输入要扫描的指定目录:>");
Scanner s = new Scanner(System.in);
String dir = s.nextLine();
File file = new File(dir);
if(!file.isDirectory()) {
System.out.println("目录不存在");
return;
}
//要查找的内容
System.out.println("请输入要查找的内容>");
String search = s.nextLine();
//递归遍历子目录
recurFile(file,search);
}
private static void recurFile(File file, String search) {
File[] files = file.listFiles();
if(files == null) {
return;
}
for (File item : files) {
// System.out.println(file.getAbsoluteFile());
if(item.isFile()) {
//获得文件的内容
String ret = getContent(item);
if(ret.contains(search)) {
System.out.println(item.getAbsoluteFile() + " " + ret);
}
} else if(item.isDirectory()) {
recurFile(item,search);
} else {
continue;
}
}
}
private static String getContent(File file) {
StringBuilder str = new StringBuilder();
try (Reader inputStream = new FileReader(file)){
int ret;
while (true) {
ret = inputStream.read();
if(ret == -1) break;
str.append((char) ret);
}
} catch (IOException e) {
e.printStackTrace();
}
return str.toString();
}
}
注:这里采用递归扫描方式并不高效,目的只是单纯熟悉文件操作.
5.拓展:try with resources 操作
try with resources操作是带有资源释放的try操作,不过一定是要实现了Closeable接口的类.因为Reader,Writer,InputStream,OutputStream类都实现了Closeable接口,所以才可以通过try with resources操作进行资源的自动释放.
分享完毕~