1.文件
1.1 基础介绍
- 文件是在硬盘上存储数据的操作,操作系统把硬盘的一些细节给封装起来了,我们只需要了解文件相关的接口即可.
- 硬盘是用来存储数据的,和内存相比,硬盘的存储空间更大,访问速度更慢,成本更低,持久化存储.
- 站在操作系统的角度看待,目录也是文件:
①普通文件(通常见到的文件)
②目录文件(通常见到的文件夹)
- 操作系统通过"文件系统"这样的模块来管理硬盘.
比如说:
这里的C,D,E盘并不是真正的硬盘,实际上电脑中只有一个硬盘,操作系统通过文件系统把这个硬盘抽象成了多个硬盘.
- 不同的文件系统,管理文件的方式是类似的,通过 目录-文件 构成了"N叉树"树形结构
1.2 文件路径
①路径:
D->tmp->bag.jpq 通过这个路线可以找到电脑上唯一一个文件,这个东西就成为"路径".
使用/或\来分割不同的目录.
②绝对路径:
以盘符开头的路径,叫做"绝对路径",相当于从"此电脑"出发,找文件的过程.(d:/tmp/bag.jpq)
③相对路径:
以.或..开头的路径,叫做"相对路径",需要一个"基准目录"/"工作目录".
比如:
如果以D:为基准目录,相对路径为./tmp/bag.jpq(这个.表示当前所在目录)
如果以D:/tmp为基准目录,相对路径为./bag.jpq(这个.表示当前所在目录)
如果以D:/tmp/11为基准目录,相对路径为../bag.jpq(这个..表示当前所在目录的上一层目录)
如果以D:/tmp/11/aa为基准目录,相对路径为../../bag.jpq
注:同样是一个cat.jpq文件,站在不同的基准目录中,查找的路径是不同的.
1.3 文件类型
文件系统上存储的文件,具体开始又分为两个大类:
①文本文件(存储的是字符)
②二进制文件(存储的是二进制的数据)
2.Java中操作文件
Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述.(io即input和output)
我们站在cpu的视角来看待输入输出:
通过File对象来描述一个具体的文件,可以对应到一个真实存在的文件,也可以对应到一个不存在的文件.
2.1 构造方法
2.2 方法
修饰符及返回 值类型 | 方法签名 | 说明 |
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() | 判断用户是否对文件有可写权限 |
3.文件内容的读写 —— 数据流
3.1 Reader用法
//Reader用法
public class Demo6 {
public static void main(String[] args) throws IOException {
//FileReader构造方法,可以填写一个文件路径(绝对路径/相对路径都行,也可以填写一个构造好的File对象)
//Reader reader = new FileReader("e:/test.txt");//抽象类
//抛出异常,或者return,这里的close就执行不到了
/*try {
}finally {
reader.close();//这个操作非常重要,释放必要的资源
//一旦一直打开文件,而不去关闭不用的文件,文件描述符表就会被占满,后续就无法继续打开新的文件
}*/
//使用try with resources是更好的解决方案
try(Reader reader = new FileReader("e:/test.txt")) {
//try代码块执行完毕,会自动调用到close方法,类似于synchronized
while (true){
char buf[] = new char[1024];//通过read,就会把本来一个空的数组,填充上内容
int n = reader.read(buf);
if (n == -1){
break;//读到文件末尾了
}
for (int i = 0; i< n; i++){
System.out.print(buf[i] + " ");
}
}
}
}
}
3.2 InputStream用法
//InputStream用法
public class Demo7 {
public static void main(String[] args) throws IOException {
try(InputStream inputStream = new FileInputStream("d:/test.txt")) {
//文本文件也可以使用字节流打开,只不过此时读到的每个字节,就不是完整字符了
while (true){
byte[] buf = new byte[1024];
int n = inputStream.read(buf);
if (n == -1){
break;
}
for (int i = 0; i < n;i++){
System.out.print(buf[i]+ " ");
}
String s = new String(buf,0,n);//字节数组转成字符串
System.out.println(s);
}
}
}
}
注:
InputStream 只是一个抽象类,要使用还需要具体的实现类。现在只关心从文件中读取,所以使用 FileInputStream
FileInputStream构造方法:
public class Demo8 {
public static void main(String[] args) throws IOException {
try(InputStream inputStream = new FileInputStream("e:/test.txt")) {
Scanner scanner = new Scanner(inputStream);
//此时就是从test.txt中读取文件了
String s = scanner.next();
System.out.println(s);
}
}
}
3.3 Writer用法
//使用Writer
public class Demo9 {
public static void main(String[] args) throws IOException {
try(Writer writer = new FileWriter("e:/test.txt",true)) {
//write可以一次直接写一个字符串,比较方便
writer.write("xixixi");
}
}
}
补充:
OutputStream使用方法一样,只不过write方法,不能支持字符串参数,只能按照字节或者字节数组来写入.
OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中, 所以使用 FileOutputStream
PrintWriter搭配OutputStream来简化代码,提供一系列方法,写的结果是写入文件中了...
4.练习
4.1 题目一
public class Demo10 {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
//1.让用户输入一个目录,后续的查找都是针对这个目录的
System.out.println("请输入要搜素的目录: ");
File rooPath = new File(scanner.next());
//2.让用户输入要搜索/删除的关键词
System.out.println("请输入要删除的关键词: ");
String word = scanner.next();
//3.判断一下当前输入的目录是否有效
if (!rooPath.isDirectory()){
System.out.println("您此时输入的路径不是合法目录!");
return;
}
//4.遍历目录,从根目录出发,按照深度优先的方式,进行遍历
scanDir(rooPath,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.getAbsoluteFile());
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)){
//此时这个文件不包含关键字,直接跳过
return;
}
//2,包含word,询问用户是否删除该文件
System.out.println("请输入该文件是:" +f.getAbsoluteFile() + "是否要删除?y/n");
String choice = scanner.next();
if (choice.equals("y")||choice.equals("Y")){
f.delete();
}
//如果是其它,忽略
}
}
4.2 题目二
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);
//不要求目标文件本身存在,要求其所在的目录存在
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[1024];
int n = inputStream.read(buffer);
System.out.println("n = " +n);
if (n ==-1){
System.out.println("读取到eof,循环结束");
break;
}
//把读到的内容写入
outputStream.write(buffer,0,n);
}
}
}
}