目录
1.认识文件
我们先来认识狭义上的文件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般。
文件除了有数据内容之外,还有一部分信息,例如文件名、文件类型、文件大小等并不作为文件的数据而存在,我们把这部分信息可以视为文件的元信息。
1.1树形结构组织和目录
同时,随着文件越来越多,对文件的系统管理也被提上了日程,如何进行文件的组织呢, 一种合乎自然的想法出现了,就是按照层级结构进行组织——也就是我们数据结构中学习过的树形结构。这样,一种专门用来存放管理信息的特殊文件诞生了,也就是我们平时所谓文件夹(folder)或者目录(directory)的概念。
2.文件路径(Path)*
2.1相对路径和绝对路径*
如何在文件系统中如何定位我们的一个唯一的文件就成为当前要解决的问题,但这难不倒计算机科学家,因为从树型结构的角度来看,树中的每个结点都可以被一条从根开始,一直到达的结点的路径所描述,而这种描述方式就被称为文件的绝对路径(absolute path)。
除了可以从根开始进行路径的描述,我们可以从任意结点出发,进行路径的描述,而这种描述方式就被 称为相对路径(relative path),相对于当前所在结点的一条路径。
我们使用“../”来表示上一级目录,“../../”表示上上级的目录,以此类推
比如当项目和文件处于同一个目录下时,相对路径为"word.txt"
当文件处于项目的上一级时,相对路径为"../word.txt"
当文件位于项目的上一级目录的子文件夹下面时,相对路径为"../word在这里!/word.txt"
3.操作文件-File类
Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。
注意:有 File 对象,并不代表真实存在该文件。
3.1属性
3.2构造方法
3.3方法
3.4代码示例
观察get系列的特点及差异
创建文件,左侧有创建出来的文本文件
删除文件,左侧文件被删除
创建目录,其中mkdir只能创建一层!pathname也只能写一层,不然会失效
文件重命名
4.文件内容的读写--数据流
4.1 InputStream
方法
InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本 可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用FileInputStream
FileInputStream 构造方法
4.2 OutputStream
OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中, 所以使用 FileOutputStream
代码示例1:
删除指定目录下的含有指定关键词的文件
import java.io.File;
import java.util.Scanner;
public class FileTest {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
// 1. 让用户输入一个目录. 后续的查找都是针对这个目录来进行的.
System.out.println("请输入要搜索的根目录: ");
File rootPath = new File(scanner.next());
// 2. 判定一下当前输入的目录是否有效.
if (!rootPath.isDirectory()) {
System.out.println("您此时输入的路径不是合法目录!");
return;
}
// 3. 再让用户输入要搜索/要删除的关键词.
System.out.println("请输入要删除的关键词: ");
String word = scanner.next();
// 4. 遍历目录. 从根目录出发, 按照 深度优先(递归) 的方式, 进行遍历
scanDir(rootPath, word);
}
public static void scanDir(File currentDir, String word) {
// 1. 先列出当前目录中都包含哪些内容.
File[] files = currentDir.listFiles();
if (files == null || files.length == 0) {
// 空的目录或者非法的目录
return;
}
// 2. 遍历列出的文件, 分两个情况分别讨论.
for (File f : files) {
// 加个日志, 方便看程序执行的过程.
System.out.println(f.getAbsolutePath());
if (f.isFile()) {
// 3. 如果当前文件是普通文件, 看看文件名是否包含了word, 来决定是否要删除.
dealFile(f, word);
} else {
// 4. 如果当前文件是目录文件, 就递归执行 scanDir
scanDir(f, word);
}
}
}
private static void dealFile(File f, String word) {
// 1. 先判定当前文件名是否包含 word
if (!f.getName().contains(word)) {
// 此时这个文件不包含 word 关键词. 直接跳过.
return;
}
// 2. 包含 word 就需要询问用户是否要删除该文件?
System.out.println("该文件是: " + f.getAbsolutePath() + ", 是否要确认删除? (Y/N)");
String choice = scanner.next();
if (choice.equals("Y") || choice.equals("y")) {
f.delete();
}
// 如果是其他值, 都忽略.
}
}
代码示例2:
进行普通文件的复制
package file;
import java.io.*;
import java.util.Scanner;
// 完成文件复制.
public class Demo11 {
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
// 1. 输入路径并且合法性判定
System.out.println("请输入要复制的源文件路径: ");
String src = scanner.next();
File srcFile = new File(src);
if (!srcFile.isFile()) {
System.out.println("您输入的源文件路径非法!");
return;
}
System.out.println("请输入要复制到的目标路径: ");
String dest = scanner.next();
File destFile = new File(dest);
// 不要求目标文件本身存在. 但是得保证目标文件所在的目录, 得是存在的.
// 假设目标文件写作 d:/tmp/cat2.jpg, 就需要保证 d:/tmp 目录是存在的.
if (!destFile.getParentFile().isDirectory()) {
System.out.println("您输入的目标文件路径非法!");
return;
}
// 2. 进行复制操作的过程. 按照字节流打开.
try (InputStream inputStream = new FileInputStream(srcFile);
OutputStream outputStream = new FileOutputStream(destFile)) {
while (true) {
byte[] buffer = new byte[20480];
int n = inputStream.read(buffer);
System.out.println("n = " + n);
if (n == -1) {
System.out.println("读取到 eof, 循环结束. ");
break;
}
outputStream.write(buffer, 0, n);
}
}
}
}
运行结果:
查看文件夹,复制成功!
利用 Scanner 进行字符读取
利用 PrintWriter 找到我们熟悉的方法
我们其实已经完成输出工作,但总是有所不方便,我们接来下将 OutputStream 处理下,使用 PrintWriter 类来完成输出,因为PrintWriter 类中提供了我们熟悉的 print/println/printf 方法
代码示例:
在output.txt中写入!