一.文件
1.定义
文件一般指的是存储在硬盘上的普通文件
形如:txt.jpg.mp4,rar等这些文件
在计算机中,文件可能是一个广义的概念,不仅可以包含普通文件,还可以包含目录(也就是文件夹.把目录称为目录文件)
在操作系统中,还会用文件来描述一些其他的硬件设备或者软件资源
比如网卡,显示器,键盘,操作系统都把这些设备视为文件
2.硬盘
普通文件是保存在硬盘上
![](https://img-blog.csdnimg.cn/img_convert/7f7ebce669dbb5349a9b2d25b8d247f2.png)
硬盘的基本构造
1.盘片,存储数据的介质
2,磁头
机械硬盘一般插上电,里面的盘片就会高速运转,磁头就在盘片上找到对应的额数据
受限于机械硬盘结构:盘片转速越高,读写速度也就越快.机械硬盘往大容量的方向发展
![](https://img-blog.csdnimg.cn/img_convert/7cd3a48302a689762960c04dc2129780.png)
3.文件的分类
1.文本文件->存储的是字符->文本文件本质上也是存字节但是在文本文件中,相邻的字节在一起正好能构成一个个字符
2.二进制文件->存储的是字节->>相邻的字节和字节之间没有关系
判断一个文件是文本还是二进制,
用记事本打开,打开是乱码 就是二进制,不是就是文本
![](https://img-blog.csdnimg.cn/img_convert/9f18c6120804418c928d28b0c02fceb9.png)
.txt .c .java都属于文本文件
.doc ,ppt .exe .zip .class 都属于二进制文件
![](https://img-blog.csdnimg.cn/img_convert/8cca4237640dce08a3efb4b5fa708618.png)
4,目录结构
计算机中爆粗能管理文件,是通过操作系统中的文件系统这样的模块来负责的
文件系统中.一般是通过"树形"结构来组织磁盘的目录和文件
就是数据结构中的N叉树
![](https://img-blog.csdnimg.cn/img_convert/4464f1ff0ff0d26a74116f2138b91078.png)
整体的文件系统.就是这样的树形结构
如果是一个普通文件,就是树的叶子结点
如果是一个目录文件目录中就可以包含子树,这个目录就是飞叶子节点
5.路径
操作系统中,路径表示一个具体文件/目录的位置
1.绝对路径,以盘符开头的
![](https://img-blog.csdnimg.cn/img_convert/9ac657b058ceb832f9e490eb917b703b.png)
2.相对路径:以 . 开头(.表示当前路径)或者以..开头的(表示当前路径的父目录,也就是上级路径)
如果是相对路径,必须要现有一个基准目录
相对路径就是从基准目录出发,按照一个什么样的路径找到的额对应文件
![](https://img-blog.csdnimg.cn/img_convert/303252c06264eb7bbd81b0068e8d550a.png)
![](https://img-blog.csdnimg.cn/img_convert/41346a296447f10542eacc3ace2d7934.png)
![](https://img-blog.csdnimg.cn/img_convert/81cfd06f3282586b215d2a7fe64e2ae6.png)
二,操作文件
1.文件系统相关的操作
通过文件资源管理器能够完成的一些功能
![](https://img-blog.csdnimg.cn/img_convert/d7e979886537aee88c0c1065785b827f.png)
在Java中提供一个File类,通过这个类来完成上述的操作
首先这个File类就描述了一个文件/目录
基于这个对象可以实现上面的功能
1.1FIle类
File的构造方法,能够传入一个路径,来指定文件,可以是绝对路径也可以是相对路径
![](https://img-blog.csdnimg.cn/img_convert/1bea40440740b985bb23ea54f4db5c4e.png)
![](https://img-blog.csdnimg.cn/img_convert/559911f0d274515be610dd9ebf6f46b8.png)
1.2基准路径
基准路径是由运行的这个java程序确定
1)如果是通过命令行的形式,此时执行命令所在目录就是基准路径
2) 如果是通过IDEA的方式运行程序那么基准路径就是java项目所在的路径
![](https://img-blog.csdnimg.cn/img_convert/7e35ced68e90cbbf4862e5b1582d00bf.png)
![](https://img-blog.csdnimg.cn/img_convert/601d5fe17cf5159cebeaaf83e00fe496.png)
3)将一个java代码达成war包.放到tomcat上运行,这种情况下,基准路径就是tomcat的bin目录
![](https://img-blog.csdnimg.cn/img_convert/2ed11bb554cfb5548a0a7da97f2af2aa.png)
1.3路径之间的分隔符
![](https://img-blog.csdnimg.cn/img_convert/d4e191492513162e3b8c1ca42a08ab96.png)
![](https://img-blog.csdnimg.cn/img_convert/844f6239ac01741fb999ae77d0465f23.png)
![](https://img-blog.csdnimg.cn/img_convert/4fe3235d0e7caa83e9741780a3e20bf6.png)
![](https://img-blog.csdnimg.cn/img_convert/a9618224e849963435fbb43efa8544d9.png)
![](https://img-blog.csdnimg.cn/img_convert/597d2dcd971e4e5db074fef74077e2a7.png)
1.4创建目录
mkdir 创建一级目录
mkdirs创建多级
![](https://img-blog.csdnimg.cn/img_convert/6b9f72b7be11e9ae7046c5f57bee9967.png)
![](https://img-blog.csdnimg.cn/img_convert/141dc05f1b30b74fda9f11666cc0639b.png)
2.流
![](https://img-blog.csdnimg.cn/img_convert/5085741407d77915dfb1bb9136202b50.png)
stream :流
![](https://img-blog.csdnimg.cn/img_convert/7154114c1fc94d78b1119202b7ed11b8.png)
2.1 FileInputStream
![](https://img-blog.csdnimg.cn/img_convert/048f8781513e5e86263529f873b8a3ff.png)
read提供了三个版本得重载
1)无参数版本:一次读一个字节.返回值是读到的这个字节
![](https://img-blog.csdnimg.cn/img_convert/27e926b8b4a0ea3a2acf685bc0df0a68.png)
如果返回的是byte,本身就是-128->+127
当读出了一个-1的时候,到底是读到文件末尾,还是说正好有个字节就是-1这个值(0xff)
为了表示这个非法状态,就约定了-1来表示,因此就需要使用一个比byte更大的范围
short或者int都行->short运算的时会自动转成int
![](https://img-blog.csdnimg.cn/img_convert/a66a3d06c6d933a74ee133c30c3f989b.png)
![](https://img-blog.csdnimg.cn/img_convert/a4136d457877de3401730508726f87d2.png)
public static void main(String[] args) {
try {
FileInputStream fileInputStream=new FileInputStream("./sun.txt");
while(true){
int a=fileInputStream.read();
if(a==-1){
break;
}
System.out.println(a);
}
} catch (IOException e) {
e.printStackTrace();
}
}
这样还不够,需要关闭文件
![](https://img-blog.csdnimg.cn/img_convert/28fa8f76b5667cea2e25949874befe4c.png)
![](https://img-blog.csdnimg.cn/img_convert/8bd63a5f04844a9178024ba25b3ae5e0.png)
这样太啰嗦了
java中提供一个语法.try with resource
![](https://img-blog.csdnimg.cn/img_convert/0768d694542691e38ec9aa7cf5bf861d.png)
这个代码中没有显示调用close.但是try会自动帮我们调用
![](https://img-blog.csdnimg.cn/img_convert/0404d42f819089f8d49677c51a974fb5.png)
![](https://img-blog.csdnimg.cn/img_convert/d1f32e981e849ed4a3cf3a3ae7ff10b4.png)
2)一个参数版本:一次读若干个字节,把读的结果放到参数指定的数组中,返回值就是读到的字节数
3)三个参数版本:一次读若干个字节,把读的结果,放到参数指定的数组中,返回值就是读到的字节数
不是从数组的起始位置放.从off下标这个位置,len表示最多能放多少个字节
![](https://img-blog.csdnimg.cn/img_convert/87e346b986d6bc78dbed88bfd9d9e2fc.png)
public static void main(String[] args) {
try {
FileInputStream fileInputStream=new FileInputStream("./sun.txt");
while(true){
int a=fileInputStream.read();
if(a==-1){
break;
}
System.out.println(a);
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.2fileOutputStream
![](https://img-blog.csdnimg.cn/img_convert/b9d5590e1fca6c9732c36a2c6cf95d90.png)
![](https://img-blog.csdnimg.cn/img_convert/ab4959721861eb351f74939b0c974dab.png)
不自动清空的话就设置为trye
![](https://img-blog.csdnimg.cn/img_convert/8efd5757952ecd808bfc278e0e95d58e.png)
![](https://img-blog.csdnimg.cn/img_convert/69db27dfeab20f66a129c08b56ba5135.png)
3.删除文件
扫描指定目录,并找到名称中包含指定字符的所有普通文件,(不包含目录).后续询问用户是否要删除文件
要求:用户输入一个目录,再输入一个要删除的文件名
文件系统上的目录是一个树形结构
二叉树的遍历就是:先序,中序,后序,层序
N叉树也是同样的道理
思路:先输入目录,判断目录是否存在,构建一个查找函数然后再遍历,如果不是文件就递归
直到找到删除文件名,然后构造一个删除函数,询问用户并删除
这里注意,判断递归结束条件的时候不能错误的以传过来的scanFile
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入你要扫描的路径");
String scanDIr=sc.next();
System.out.println("请输入你要删除的文件名");
String toDeleteFile=sc.next();
File scanFile=new File(scanDIr);
if(!scanFile.isDirectory()){
System.out.println("非法路径");
return;
}
scaAndDelFile(scanFile,toDeleteFile);
}
private static void scaAndDelFile(File scanFile, String toDeleteFile) {
//1.先列出scanFile有哪些内容
File[] files=scanFile.listFiles();
if(files==null){
return;//不能对传过来的scan进行判断,因为他既然能传过来就说明不是空的,只有可能他有这个容器但是他下面的东西是空的,
}
//2.分别列出来然后遍历
for (File f:files){
if(f.isFile()){
if(f.getName().contains(toDeleteFile)){
deleteFile(f);
}
}
if (f.isDirectory()){
scaAndDelFile(f,toDeleteFile);
}
}
}
private static void deleteFile(File scanFile) {
System.out.println("确定要删除吗>(Y/y)");
Scanner scanner=new Scanner(System.in);
String str=scanner.nextLine();
if(str.equals("Y")||str.equals("y")){
scanFile.delete();
System.out.println("删除成功");
}else{
System.out.println("删除取消");
return;
}
}
4.复制文件
需要让用户指定两个文件路径,一个是原路径,一个是目标路径
打开源文件的文件,读取里面的内容,并写入到目标文件
扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件
![](https://img-blog.csdnimg.cn/img_convert/4d87d1a5956500c0fbb958f6e8f5f7a9.png)
public static void main(String[] args) {
// 1. 输入两个路径
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要拷贝的源路径: ");
String src = scanner.next();
System.out.println("请输入要拷贝的目标路径: ");
String dest = scanner.next();
File srcFile = new File(src);
if (!srcFile.isFile()) {
System.out.println("输入的源路径不正确!");
return;
}
// 此处不太需要检查目标文件是否存在. OutputStream 写文件的时候能够自动创建不存在的文件.
// 2. 读取源文件, 拷贝到目标文件中
try (InputStream inputStream = new FileInputStream(src)) {
try (OutputStream outputStream = new FileOutputStream(dest)) {
// 把 inputStream 中的数据读出来, 写入到 outputStream 中
byte[] buffer = new byte[1024];
while (true) {
int len = inputStream.read(buffer);
if (len == -1) {
// 读取完毕
break;
}
// 写入的时候, 不能把整个 buffer 都写进去. 毕竟 buffer 可能是只有一部分才是有效数据.
outputStream.write(buffer, 0, len);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
更高效的全文检索->倒排索引的结构
5..flush->刷新缓冲区
缓冲区存在的意义就是为了提高效率
CPU读取内存的速度远远高于硬盘
例如
①需要写数据到硬盘上,与其一次写一点,分多次,还不如把数据攒一起,统一写,这一堆待写的数据就是在内存中保存的,这块内存就叫缓冲区
②读操作也是类似,与其一次读一点,分多次多,不如一次性读一堆数据,然后再慢慢消化
③:写数据的时候需要把数据写到缓冲区,然后再统一写到硬盘上
如果当前缓冲区已经写满了,直接触发写硬盘操作
如果当前缓冲区没满,也想提前写硬盘,就可以通过flush手动刷新缓冲区
close操作也会触发缓冲区刷新