目录
文本文件和二进制文件
File概述
递归去查看某个目录下的所有文件与目录
InputStream概述
OutputStream 概述
文件操作的应用
面试题:递归文件路径并且删除指定文件
将一个指定路径的文件复制到另一个文件中去
1.文件
此处的文件有多种含义,不仅仅包括硬盘上的文件以及保存文件的目录,还包括许多的硬件设备,软件资源。
2.硬盘
硬盘与内存对比:
1.硬盘的储存空间大大,内存的储存空间小
2.硬盘的速度慢,内存的速度块
3.硬盘的成本低,内存的成本高
4.硬盘能够持久化储存,内存断电后数据消失。
3.文件系统
文件系统上的目录结构是一个树形结构,是N叉树。
4.文件路径
在文件系统中如何定位我们的一个唯一的文件是重要的难题。从文件的分布的树形结构来看,每个节点都可以从一条跟开始,一直到节点所在的路径来描述。这就是绝对路径。
除了从根节点开始进行路径的描述,也可以从任意节点出发,进行路径的描述,这种描述路径的方式就是相对路径,相对于当前所在节点的一条路径。
文本文件和二进制文件
文本文件:当前文件里储存的所有内容都是”文本“都是合法的字符,这些字符的编码方式按照字符集。虽然叫做文本文件但是内部还是二进制,只不过这些二进制有据可查。文本文件底层虽然是二进制储存,但是java在把文本文件读取出来的时候会自动查询码表,把二进制转化成一个个字符。而二进制文件则没有上述转换过程。
二进制文件:顾名思义就是里面储存二进制的文件。一般这种文件不能被直接打开,而是要通过特定的应用程序打开。
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(File dest) | 进⾏⽂件改名,也可以视为我们平时的剪切、粘贴操作 |
boolean | canRead() | 判断⽤⼾是否对⽂件有可读权限 |
boolean | canWrite() | 判断⽤⼾是否对⽂件有可写权限 |
说明一下,上述方法有的在使用的时候要声明一下IOException异常
1.因为有可能在使用文件的时候硬盘空间会不够用。
2没有权限,确保有权限操作文件的时候才能进行程序。读权限/写权限等待
通过renameTo(File dest)可以实现文件的转移。
递归去查看某个目录下的所有文件与目录
文件内容的读写——数据流
InputStream概述
修饰符及返回值类型 | ⽅法签名 | 说明 |
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() | 关闭字节流 |
InputStream只是一个抽象类,要使用还需要具体的实现类。关于InputStram的实现类有很多,基本可以认为不同的输入设备都能对应一个InputStream类,现在只关心从文件中读取,所以使用FileInputStream
FileInputStream概述
签名 | 说明 |
FileInputStream(File file) | 利⽤ File 构造⽂件输⼊流 |
FileInputStream(String name) | 利⽤⽂件路径(绝对/相对路径)构造⽂件输⼊流 |
此处隐含了一个打开文件,针对文件的读写必须先打开文件。
既然打开文件,那么就要关闭文件。打开文件其实就是打开进程的文件描述符表中,在里面创建一个新的项目。
文件描述符表可以认为是一个数组,描述了进程打开了哪些文件。每打开一项进程描述符表就多处一项信息,但是这个数组的长度是固定,如果打开文件后不及时主动关闭,一直打开不去关闭,,这里的资源就会越来越少,最后数组的空间满了就会打开失败。不及时释放就会造成内存泄漏。
为了防止忘记colse,就可以把InputStream放入try语句中,每次try执行完就会自动调用colse。
因为InputStream继承了Closeable接口,
OutputStream 概述
⽅法
修饰符及返回值类型 | ⽅法签名 | 说明 |
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 同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件中,所以使⽤ FileOutputStream
InputStresm 和 OutputStream 是用于读写字节流的,读写数据的基本单位是字节。
Reader 和 Writer 用于读写字符流的,读数据的基本单位是字符。字符流内部做的工作会更多一些,读取到的字符会自动查询码表,把二进制数据转换成字符。
但是是以Rean/Write结尾的就是实现了Read/Write对象,以InputStream/OutStream结尾的就是实现了InputStream/OutputStream的字节流对象。
什么是输入输出?
以cpu的视角来看,数据远离cou就是输出,数据靠近cpu就是输入。
文件操作的应用
1.两中不同的方式读文件
使用InputStream读取文本,一次读取一个字节
一次读取多个字节
使用OutputStream输入字节,一个出入多个
使用Reader读取字符
使用Reader读取多个字符存放在数组里
使用Write写入
利⽤ Scanner 进⾏字符读取
上述例⼦中,我们看到了对字符类型直接使⽤ InputStream 进⾏读取是⾮常⿇烦且困难的,所以,我们使⽤⼀种我们之前⽐较熟悉的类来完成该⼯作,就是 Scanner 类。
构造⽅法 | 说明 |
Scanner(InputStream is, String charset) | 使⽤ charset 字符集进⾏ is 的扫描读取 |
面试题:递归文件路径并且删除指定文件
private static void scan(File srcFilePath,String nameFile){
if(!srcFilePath.isDirectory()){
return;
}
File[] files = srcFilePath.listFiles();
if(files == null || files.length == 0){
return;
}
for (File f:files) {
if(f.isFile()){
//是否删除文件
doDelete(f,nameFile);
}
else scan(f,nameFile);
}
}
private static void doDelete(File file,String nameFile){
if(!file.getName().contains(nameFile)){
return;
}
Scanner scanner = new Scanner(System.in);
System.out.println("是否删除文件? Y/N");
String answer = scanner.nextLine();
if(answer.equals("Y") || answer.equals("y")){
file.delete();
System.out.println("删除成功");
}
}
public static void main(String[] args) {
System.out.println("请输入源路径");
Scanner scanner = new Scanner(System.in);
String srcFilePath = scanner.nextLine();
File srcfilePath = new File(srcFilePath);
if(!srcfilePath.isDirectory()){
System.out.println("输入路径错误");
return;
}
System.out.println("请输入文件名称");
String nameFile = scanner.nextLine();
File srcFile = new File(nameFile);
scan(srcfilePath,nameFile);
}
将一个指定路径的文件复制到另一个文件中去
//将一个文件复制到另一个文件中去
public static void main(String[] args) {
System.out.println("输入源文件路径");
Scanner scanner = new Scanner(System.in);
String srcFilePath = scanner.nextLine();
File srcfile = new File(srcFilePath);
if(!srcfile.isFile()){
System.out.println("源文件路径有误");
return;
}
System.out.println("输入目标文件路径");
String destFilePath = scanner.nextLine();
File destfile = new File(destFilePath);
if(!destfile.isFile()){
System.out.println("目标文件路径有误");
return;
}
try (InputStream inputStream = new FileInputStream(srcfile);
OutputStream outputStream = new FileOutputStream(destfile)){
while (true){
byte[] buffer = new byte[1024];
int n = inputStream.read(buffer);
if(n == -1) return;
outputStream.write(buffer,0,n);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}