文件:
操作系统中会把很多 硬件设备 和 软件资源 抽象成“文件”,统一进行管理。
大部分谈到的文件,都是指 硬盘的文件,文件就相当于是针对“硬盘”数据的一种抽象
硬盘:
1.机械硬盘:便宜
2.固态硬盘:比机械硬盘效率高(类似于内存,cpu)
现在电脑基本都是固态硬盘,想存储更多资料就可以额外添加机械硬盘。
机械硬盘不可拆开!!!会沾满灰尘,撞坏磁头。
机械硬盘适合顺序读写,,不适合随机读写。
在服务器开发中,涉及到硬盘有机械,也有固态。在一些用来存储大规模的机器中,仍然以机械硬盘为主。
内存 VS 硬盘
1.内存速度快,硬盘速度慢
2.内存空间小,硬盘空间大
3.内存贵,硬盘便宜
4.内存数据,断电丢失;硬盘数据,断电存在
以文件的方式操作硬盘
计算机上的文件通过“文件系统”(操作系统提供的模块)来进行组织。
操作系统使用 “目录”这样的结构来组织文件 ----->树形结构
通过目录这样的层次结构,描述文件所在位置--->路径“path”
路径:
1.绝对路径:以C: D: 盘符开头的
2.相对路径:需要先指定一个目录,作为基准目录 ,从基准目录出发,看看沿着那些路线能找到指定文件。往往以 . (当前目录,可省略)或者 .. (当前目录的上一级目录)开头
如果进行命令行操作,基准目录就是当前所处的目录:
如果是图形化界面,基准目录不好说,对于idea来说,基准目录就是项目目录:
文件的类型:
1.文本:文件中保存的数据,都是字符串,保存内容都是合法字符
2.二进制:文件中保存的数据,仅仅是二进制字符,不要求保存的内容是合法字符
合法字符:字符集/字符编码
Eg:
Utf8
有一个表格列出了什么字符对应什么编码
如果文件是utf8编码,文件中的每个数据都是合法的utf8编码的字符,就可以认为是文本文件。
如果存在一些不是utf8合法字符的情况,就是二进制文件。
计算机本身存储的数据都是二进制
如何判定一个文件是文本文件还是二进制文件?
把这个文件放入到记事本中,看是否出现乱码。
无乱码则是文本文件,有乱码则是二进制文件。
(记事本尝试按照字符的方式来展示内容,这个过程会自动查码表)
写代码时,文本文件和二进制文件,代码编写方式不同。
docx、pptx都都属于二进制
文本文件
Java对于文件操作的api
1.针对文件系统进行操作(右键目录)
:创建文件、删除文件、重命名文件。。。
2.针对文件内容的操作:流对象
:读文件/写文件
Java针对文件系统的操作,使用File类进行操作。
这个类所在的包, 叫java.io。
IO:Input->输入
Ouput->输出
输入和输出:
pathSeparator:在一个路径中用来分隔目录的符号,开发中建议用 “/”
文件名=前缀+扩展名
使用路径构造File对象时,要把前缀和扩展名都加上。
文件都有权限
删除
package Io;
import java.io.File;
public class Demo3{
public static void main(String[] args) throws InterruptedException {
File file = new File("d:/test.txt");
// boolean ret = file.delete();//删除文件
// System.out.println("ret = " + ret);
file.deleteOnExit();//退出之后再删除
Thread.sleep(5000);//5s之后
System.out.println("进程结束!");
}
}
打印指定路径下的文件和目录
package Io;
import java.io.File;
import java.util.Arrays;
public class Demo4{
public static void main(String[] args) {
File file = new File("d:/");
String[] list = file.list();
System.out.println(Arrays.toString(list));
}
}
创建目录
package Io;
import java.io.File;
public class Demo5 {
public static void main(String[] args) {
File file = new File("d:/java学习/aaa/bbb/ccc");
// boolean ret = file.mkdir();//创建file对象代表下的目录
boolean ret = file.mkdirs();//创建file对象代表下的多级目录
System.out.println("ret = " + ret);
}
}
重命名
package Io;
import java.io.File;
public class Demo6 {
public static void main(String[] args) {
File srcfile = new File("D:/test.txt");
File destfile = new File("D:/test2.txt");
boolean ret = srcfile.renameTo(destfile);//重命名
System.out.println("ret = "+ret);
}
}
流对象:对文件内容操作
标准库中,提供读写文件的流对象,有多个类。大体分为两个类别:
1.字节流(对应着二进制文件):每次读/写的最小单位,都是“字节”。
代表类:
--》InputStream 输入
--》OutputStream 输出
2.字符流(对应着文本文件):每次读/写的最小单位,都是“字符”。
一个字符可能对应多个字节 --> 看当前的字符集
GBK -> 一个中文字符 =》两个字节
UTF8 ->一个中文字符 =》三个字节
(字符流是对字节流进行的又一层封装。能帮我们把文件中几个相邻的字节,转换成一个字符。帮我们完成一个自动查字符集表)
代表类:
--》Reader
--》Writer
字符流:
Reader
package Io;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class Demo7 {
public static void main(String[] args) throws IOException {
//文件不存在会抛异常,原本FileReader会抛一个FileNotFoundException,read会抛一个IOException,由于FileNotFoundException是IOException的子类
// Reader reader = new Reader("d:/test.txt");//Reader是抽象类,不能new实例,只能new子类
// Reader reader = new FileReader("d:/test.txt");//创建reader的过程就是打开文件的过程
//1.一次read一个字符
// while(true) {
// int c = reader.read();//由于read方法可能会返回一个-1,char表示不了,所以用int
// if(c == -1) break;
// char ch = (char)c;
// System.out.println(ch);
// }
// //2.一次read多个字符
// while(true) {//加while的原因是文件太大,数组长度不够,一次不能将文件读完,多次循环才可
// char[] cbuf = new char[1024];//创建一个字符数组
// int n = reader.read(cbuf);//n表示当前读到的字符的个数
// if(n == -1 ) {//文件为空
// break;
// }
// System.out.println("n = " + n);
// for (int i = 0; i < n; i++) {
// System.out.println(cbuf[i]);
// }
// }
//3.文件用完得close
// try {
// while(true) {
// char[] cbuf = new char[2];
// int n = reader.read(cbuf);
// if(n == -1) {
// break;
// }
// System.out.println("n = " + n);
// for (int i = 0; i < n; i++) {
// System.out.println(cbuf[i]);
// }
// }
// }finally {
// reader.close();
// }
//try with resources:括号里的reader会在try代码块结束的时候(无论是正常结束还是抛异常),都会自动调用其中的close方法
try(Reader reader = new FileReader("d:/test.txt")) {
while(true) {
char[] cbuf = new char[2];
int n = reader.read(cbuf);
if(n == -1) {
break;
}
System.out.println("n = " + n);
for (int i = 0; i < n; i++) {
System.out.println(cbuf[i]);
}
}
}
}
}
输出型参数:
释放资源:
方法一:
方法二:
方法三:
Writer
字节流:
InputStream
OutputStream
如果已知字节流对象 实际的数据 是文本数据,可以通过以下的方法将 字节流 转换成 字符流
面试题:
//扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件。
package Io;
import java.io.File;
import java.util.Scanner;
public class Demo13 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//1.先让用户输入一个要扫描的目录
System.out.println("请输入要扫描的路径:");
String path = scanner.nextLine();
File rootPath = new File(path);
if(!rootPath.isDirectory()) {
//如果此时不是目录
// 对用户输入的内容一定要进行合法性验证!!!!!
System.out.println("您输入的路径有误!!!");
return;
}
//2.让用户再输入一个查询的关键词
System.out.println("请输入要删除文件的关键词:");
String word = scanner.nextLine();
//3.进行递归扫描
scanDir(rootPath,word);
}
private static void scanDir(File rootPath, String word) {
//1.先列出路径中 所有的文件和目录
File[] files = rootPath.listFiles();
if(files == null) {
//当前目录为空,直接返回
return;
}
//2.遍历这里的每个元素,针对不同类型做出处理
for(File file : files) {
//加个日志,方便观察当前文件递归的执行过程
System.out.println("当前扫描的文件:" + file.getAbsolutePath());
if(file.isFile()) {
//普通文件,检查文件是否需要删除,并执行是删除操作
checkDelete(file,word);
}else {
scanDir(file,word);
}
}
}
private static void checkDelete(File file, String word) {
if(!file.getName().contains(word)) {
//不含关键词
return;
}
//需要删除的
System.out.println("当前文件为: " + file.getAbsolutePath() + ", 确定要删除(Y/N): ");
Scanner scanner = new Scanner(System.in);
String choice = scanner.nextLine();
if(choice.equals("Y") || choice.equals("y")) {
//真正删除
file.delete();
System.out.println("删除完毕!");
}else {
//输入其他值都会取消删除操作
System.out.println("取消删除!");
}
}
}