目录
认识文件
文件在计算机中,使保存到 硬盘 上的
硬盘通过 文件资源管理器 来管理文件
通过类似于“树形结构”管理所有文件的
通过“文件路径”的概念 描述一个文件
从根节点一直到该文件,过程中遇到的每一个目录的集合就是 文件路径
文件路径中的每一级目录 都是用 \ 来分割(Windows独有的设定,其他操作系统都是用 / )
例如:D:\游戏\aa\bbb
路径
以盘符开头的路径,也称为“绝对路径”
和绝对路径并列,还有一种表示方式叫 相对路径【通常是以 . 或者 . . 开头的路径】
例如 ./bbb
谈到 相对路径 一定要明确相对路径的 “参考系” 是什么(即相对哪个目录【工作目录\基准目录】,以哪个目录为起点来进行 “相对” 的)
例如:
绝对路径为 D:\游戏\aa\bbb
设基准路径是 D:\游戏\aa ,则相对路径为 ./bbb
光靠相对路径是无法定位文件的,要结合基准路径才可以锁定文件的具体位置
定位同一个文件,如果基准路径不同,那么相对路径也不同
如:
绝对路径为 D:\游戏\aa\bbb
设基准路径是 D:\游戏,则相对路径为 ./aa/bbb
即 基准路径 + 相对路径 = 绝对路径
. ./ 的使用
假设有这样两个文件路径:
D:\游戏\Epic Games\DirectXRedist\sugarsalt
D:\游戏\Epic Games\DirectXRedist\aaa
想要通过 D:\游戏\Epic Games\DirectXRedist\aaa 找到 sugarsalt 文件,可以用 . ./sugarsalt
即 . ./ 表示当前路径的上级目录,在上面的示例中就相当于 略过了 \aaa 从 D:\游戏\Epic Games\DirectXRedist 往后找文件
D:\游戏\Epic Games\DirectXRedist\sugarsalt
D:\游戏\Epic Games\DirectXRedist\aaa\bbb 还是要通过下面的路径找上面的 sugarsalt
用 . ./. ./sugarsalt
文件的种类
所有的文件 分为两个大类:
- 文本文件
文本文件存的都是 字符串,都是“合法的字符”【能在 utf-8 查到编码规则的】(.txt;.java;.c 都是文本文件) - 二进制文件
二进制文件存啥都行
简单判断一个文件是否是文本文件:
把该文件拖动到记事本中,如果没变成乱码,就是文本文件,否则是二进制文件
Java中操作文件
文件系统操作
创建文件,删除文件,移动文件,获取文件属性…
File 类
构造File 对象,核心就是指定 “路径”(绝对路径,相对路径)
- 构造方法
File (File parent, String child)
根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实例
File(String pathname)
根据⽂件路径创建⼀个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, String child)
根据父目录+孩子文件路径,创建一个新的File实例,父目录用路径表示
使用举例:
File file=new File("d:/hello.txt");//绝对路径创建
File file1=new File("./hello.txt");//相对路径创建
相对路径在ideal 这类开发工具来说,能看到基准路径,例如在ideal 点击快捷键 ait+F12
补充:
PS 全称为 Power Shell 是Windows上的终端的名字
- 方法
修饰符及返回值类型 方法签名 说明
String getParent() 返回 File 对象的父目录文件路径
String getName() 返回 FIlle 对象的纯文件名称
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() 判断用户是否对文件有可写权限
代码示例
首先我的D盘里面有hello.txt文件
而相对路径没有创建hello.txt 文件
- 普通⽂件的创建、删除
- list() 和 listFiles()
这两个都是针对目录操作,对文件没什么用
- mkdir() 和 mkdirs()
mkdir() 支持创建一层目录,mkdirs() 支持创建多层目录
mk==>make
dir==>directory
- renameTo
renameTo 不光能重命名,还能切换位置
文件内容操作(读写)–数据流
1.读文件:硬盘上的数据读到内存
2.写文件:把内存数据写到硬盘
基本使用逻辑:
- 打开
- 读/写
- 关闭
可以使用流对象进行文件内容操作(流——Stream)
可以把数据简单理解为水池中的水,写文件相当于往里面滴水【输出流】,读文件相当于往外流水【输入流】
Java通过一系列的类来表示“流对象”
- 字节流【读写数据的时候,以字节为基本单位,一次最少读写一个字节】
InputStream —— 读
OutputStream —— 写- 字符流【读写数据的时候,以字符为基本单位,一次最少读写一个字符】
Reader ——读
Writer —— 写(一个字符可能对应多个字节,主要看编码方式)
读写二进制文件,通常使用字节流
读写文本文件,通常使用字符流
InputStream 概述
InputStream 是一个抽象类,不能创建实例,所以我们可以实例化它的子类FileInputStream
(字节内容更习惯采用十六进制表示)
方法
修饰符及返回值类型 ⽅法名 说明
int read() 一次读取一个字节,返回 -1 代表已经完全读完了
int read(byte[] b) 一个参数版本,尝试把这个参数中的字节数组填满
int read(byte[] b, int off, int len) 最多读取 len - off 字节的数据到 b中,从 off 开
始,返回实际读到的数量;-1 代表以及读完了
FileInputStream
代码示例
此处的 bytes 参数,称为”输出型参数”
事先构造好一个空的数组 (不是 null, 里面的元素全0的数组)
由read 方法内部, 往参数数组中进行填充
Java 中一个方法,只能返回一个值
如果需要返回多个值,要么借助输出型参数,要么把返回的多个值打包成一个类
所以要把 bytes 的返回值打包给 read
read 会尽可能把 bytes 填满
注意:
使用完了这个文件一定要关闭文件
原因:进程 PCB 中有一个属性,文件描述符表 (顺序表)
每次打开一个文件,就会在这个表里插入一个元素
文件描述符表,长度是定长的(不能自动扩容)
光打开文件,不关闭文件,此时就会逐渐把这个表里的内容消耗殆尽;后续再尝试打开,就会打开失败

try(InputStream inputStream=new FileInputStream("./hello.txt")){
while (true){
byte[] bytes=new byte[1024];
int c=inputStream.read(bytes);
if(c==-1)
break;
for (int i = 0; i < c; i++) {
System.out.printf("0x%x\n",bytes[i]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
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(刷新)操
作,将数据刷到设备中。
代码示例:
发现每次写文件后原来的内容被清空了,每次按照写文件的方式打开文件,就会清空文件的原有内容
如果想要保存原有内容,可以在new文件的时候往后加一个 true
这个表示“追加写”
不会清空原有内容,新写入的内容就会从文件末尾继续追加
Reader 和 Writer
与InputStream 用法类似,只是它返回的是字符
代码示例:
小程序练习
1.通过用户输入目录和文件名找到想搜索的文件位置
import java.io.File;
import java.util.Scanner;
public class learn1 {
public static void main(String[] args) {
System.out.println("请输入你想搜索的目录:");
Scanner scanner=new Scanner(System.in);
String Dir=scanner.next();
System.out.println("输入你想搜索的文件名:");
String fileName=scanner.next();
File rootDir=new File(Dir);
if(!rootDir.isDirectory()){
System.out.println("目录不存在!");
}else {
scanDir(rootDir,fileName);//递归查找文件
}
}
public static void scanDir(File rootDir, String fileName){
File[] files=rootDir.listFiles();
if(files==null){
return;//文件找到底,递归结束
}
for (File file:files){
if(file.isDirectory()){//还是目录,再次递归
scanDir(file,fileName);
}else if(file.isFile()){
if(file.getName().contains(fileName)){//找到了
isDelete(file);
}
}
}
}
public static void isDelete(File file){
System.out.println("找到了,是否删除(Y/N)");
System.out.println(file.getAbsolutePath());
Scanner scanner=new Scanner(System.in);
String s=scanner.next();
System.out.println();
if(s.equals("Y") || s.equals("y")){
file.delete();
System.out.println("删除成功");
}
}
}
2.普通文件的复制
import java.io.*;
import java.util.Scanner;
public class learn2 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("清输入源文件:");
String file=scanner.nextLine();
System.out.println("请输入目标文件:");
String file1=scanner.nextLine();
File srcfile=new File(file);
File desFile=new File(file1);
if(!srcfile.isFile()){
System.out.println("该文件不存在!");
return;
}
File parentFile=desFile.getParentFile();
if(!parentFile.isDirectory()){
System.out.println("目标文件的父文件不存在!");
return;
}
copy(srcfile,desFile);//复制文件,进行读写操作
}
public static void copy(File srcFile,File desFile){
try(InputStream inputStream=new FileInputStream(srcFile);
OutputStream outputStream=new FileOutputStream(desFile)){
while (true){
byte[] bytes=new byte[1024];
int c=inputStream.read(bytes);
if(c==-1){
break;
}
outputStream.write(bytes,0,c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用如下: