一、文件分类
在计算机中,文件是一个广义的概念,不只是包含普通文件,还可以包含目录(把目录称为目录文件)日常所说的文件夹。
操作系统中,还会使用文件来描述一些其他的硬件设备或者软件资源~~
站在程序猿的角度,主要把文件分成两类:
①.文本文件---》里面存储的是字符----》文本文件本质上也是村字节的.但是文本文件中,相邻的字节在一起正好能构成一个个字符~~
②.二进制文件----》存储的是字节
判定一个文件是文本还是二进制,一种简单的方法:用记事本打开~如果打开之后是乱码,就是二进制,不是乱码就是文本~
像日常中使用的 .txt、.c、.java都属于文本文件,.doc、.ppt、.exe、.zip、.class等等都属于二进制文件~~word、excel office 系列的文件一般都是二进制的~~
计算机里,保存管理文件是通过操作系统中的“文件系统”这样的模块来负责的~~
文件系统中,一般是通过“树形”结构来组织磁盘上的目录和文件的~~
在操作系统中,通过“路径”这样的概念来描述一个具体文件/目录的位置,路径有两种描述风格:
1.绝对路径:以盘符开头的.E:\JavaWork\JDBC\src
2.相对路径:以.或者..开头的,其中.表示当前路径,..表示当前路径的父目录(上级路径)
谈到相对路径,必须要先有一个基准目录~~相对路径就是从基准目录出发,按照一个啥样的路径找到对应的文件~~
二、Java操作文件
1.文件系统相关的操作
指的是通过“文件资源管理器”能够完成的一些功能~~
在JAVA中提供了一个File类,通过这个类来完成上述操作.首先这个File类就描述了一个文件/目录,基于这个对象就可以实现上面的功能~~
相对路径,明确“基准路径”:
1、如果通过cmd的方式,此时执行命令所在的目录,就是基准路径~~
2、如果是通过IDEA的方式来运行程序,此时基准路径就是当前java项目所在的路径~~
在IDEA中直接运行,基准路径就是上述目录~
3、把一个java代码打包成war包,放到tomcat上运行。这种情况下基准路径就是tomcat的bin目录~~
public class Demo1 {
public static void main(String[] args) throws IOException {
File file = new File("E:\\JavaWork\\test.txt");
System.out.println(file.exists());//文件是否存在
System.out.println(file.getParent());//获取到文件的父目录
System.out.println(file.getName());//获取文件名
System.out.println(file.getAbsoluteFile());//获取到绝对路径
System.out.println(file.getCanonicalFile());//获取到绝对路径
System.out.println(file.getPath());//获取到文件路径(构建File的时候指定的路径)
System.out.println("===================");
File file1 = new File("..\\test.txt");
System.out.println(file1.exists());//文件是否存在
System.out.println(file1.getParent());//获取到文件的父目录
System.out.println(file1.getName());//获取文件名
System.out.println(file1.getAbsoluteFile());//获取到绝对路径
System.out.println(file1.getCanonicalFile());//获取到绝对路径,得到的是化简过得绝对路径
System.out.println(file1.getPath());//获取到文件路径(构建File的时候指定的路径)
}
}
判断文件是否存在,如若不存在,则创建文件,并查看之后是否存在:
public class Demo2 {
public static void main(String[] args) throws IOException {
File file = new File("./test1.txt");
System.out.println(file.exists());
System.out.println("创建文件~");
file.createNewFile();
System.out.println("创建文件结束");
System.out.println(file.exists());
}
}
删除文件的操作:
public class Demo3 {
public static void main(String[] args) {
File file = new File("./test1.txt");
file.delete();
}
}
创建目录:
public class Demo5 {
public static void main(String[] args) {
File file = new File("./aaa");
file.mkdir();//创建目录
System.out.println(file.isDirectory());
File file1 = new File("./first/second/third");
file1.mkdirs();//创建多级目录
System.out.println(file1.isDirectory());
}
}
罗列某个目录下所包含的文件:
public class Demo4 {
public static void main(String[] args) {
File file = new File("./first");
System.out.println(Arrays.toString(file.list()));
}
}
重命名:
public class Demo6 {
public static void main(String[] args) {
File file = new File("./first");
File file1 = new File("第一");
file.renameTo(file1);
}
}
2.文件内容相关的操作
核心操作:打开文件、读文件、写文件、关闭文件
针对文件内容的读写,Java标准库提供了一组类,首先按照文件的内容,分成两个系列:
(一).字节流对象,针对二进制文件,是以字节为单位进行读写的
读:InputStream
public class Demo7 {
public static void main(String[] args) throws IOException {
//构造方法中需要指定打开文件的路径
//可以是绝对路径,也可以是相对路径,还可以是File对象
//1.创建对象,打开文件
InputStream inputStream = new FileInputStream("./test.txt");
//2.尝试一个字节一个字节的读,把整个文件都读完
while (true){
int b = inputStream.read();
if(b == -1){//读到了文件末尾
break;
}
System.out.println(b);
}
//3.读完之后关闭文件
inputStream.close();
}
}
此时读出来的这些数字,就是每个字符的ascii码值,由于这些英文字符本身就是一个字节的,这里按照字节读取的效果就是如此~~
如果上述代码执行到一半捕捉到了异常,那如何才能关闭InputStream呢?
public class Demo7 {
public static void main(String[] args) {
//构造方法中需要指定打开文件的路径
//可以是绝对路径,也可以是相对路径,还可以是File对象
//1.创建对象,打开文件
try(InputStream inputStream = new FileInputStream("./test.txt");){
//2.尝试一个字节一个字节的读,把整个文件都读完
while (true){
int b = inputStream.read();
if(b == -1){
break;
}
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
在这个代码中,没有显式的调用close,
但是try会帮我们自动调用~~当代码执行完这里的try语句块之后,就会自动的调用close
*/
得符合一定的条件,才能放到try()中,实现Closeable这个interface,恰好所有的流对象,都实现了Closeable~~所以就可以直接释放了~~~
public class Demo8 {
public static void main(String[] args) {
try(InputStream inputStream = new FileInputStream("./test.txt")) {
//一次性读取若干字符
while (true){
byte[] buffer = new byte[1024];
int len = inputStream.read(buffer);
if(len == -1){
//如果返回-1,说明读取完了
break;
}
for (int i = 0; i < len; i++) {
System.out.println(buffer[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
写:OutputStream
//使用字节流写文件
public class Demo9 {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("./test.txt")) {
//一次写一个字符
// outputStream.write(97);
// outputStream.write(98);
// outputStream.write(99);
//一次写多个字符
byte[] buffer = new byte[]{97,98,99};
outputStream.write(buffer);
}catch (IOException e) {
e.printStackTrace();
}
}
}
每次按照写方式打开文件,都会清空原有文件内容,清空旧的内容,再从起始位置往后写的~~
还有一种追加写的流对象,打开之后不清空,从文件末尾继续往后写~~
需要在构造时,参数设为true~~~
try(OutputStream outputStream = new FileOutputStream("./test.txt",true)
(二).字符流对象,针对文本文件,是以字符为单位进行读写的
读:Reader
//按照字符来读写
public class Demo10 {
public static void main(String[] args) {
try (Reader reader = new FileReader("./test.txt")){
//按照字符来读
while (true){
char[] buffer = new char[1024];
int len = reader.read(buffer);
if(len == -1){
break;
}
for (int i = 0; i < len; i++) {
System.out.println(buffer[i]);
}
// String s = new String(buffer,0,len);
// System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
写:writer
//按照字符来写
public class Demo11 {
public static void main(String[] args) {
try (Writer writer = new FileWriter("./test.txt")){
writer.write("xyz");
} catch (IOException e) {
e.printStackTrace();
}
}
}
三.案例
案例一:
//文件操作案例1:扫描指定目录,再输入一个要删除的文件名,
public class Demo12 {
public static void main(String[] args) {
//1.先输入要扫描的目录,以及要删除的文件名
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要扫描的路径:");
String rootDirPath = scanner.next();
System.out.println("请输入要删除的文件名:");
String DeleteName = scanner.next();
File rootDir = new File(rootDirPath);
if(!rootDir.isDirectory()){
System.out.println("输入的扫描路径有误~~");
return;
}
//2.遍历目录,把指定目录中的所有文件和子目录都遍历一遍,从而找到要删除的文件
//通过这个方法,来实现递归遍历并删除的操作
scanDir(rootDir,DeleteName);
}
private static void scanDir(File rootDir, String deleteName) {
//1.先列出rootDir中都有哪些内容
File[] files = rootDir.listFiles();
if(files == null){
//rootDir当前这是一个空目录
return;
}
//2.遍历当前列出的这些内容,如果是普通文件,就检测文件名是否是要删除的文件
// 如果是目录,就递归的进行遍历
for (File f: files) {
if(f.isFile()){
//如果是普通文件
if(f.getName().contains(deleteName)){
//不要求名字完全一样,只要文件名中包含了关键字即可删除
deleteFile(f);
}
}else if(f.isDirectory()){
//是目录,就递归
scanDir(f,deleteName);
}
}
}
private static void deleteFile(File f) {
try {
System.out.println(f.getCanonicalFile() + "确认要删除嘛?Y/N");
Scanner scanner = new Scanner(System.in);
String str = scanner.next();
if(str.equals("Y") || str.equals("y")){
f.delete();
}else if(str.equals("N") || str.equals("n")){
System.out.println("取消删除~");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
案例二:
需要让用户指定两个文件路径,一个是原路径(被复制的文件)一个是目标路径(复制之后生成的文件),打开源路径的文件,读取里面的内容,并且写入到目标文件~~
//案例二:进行普通文件的复制~~
public class Demo13 {
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();
}
}
}
案例三:
扫描指定路径,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
public class Demo14 {
public static void main(String[] args) throws IOException {
//1.输入要扫描的文件路径
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要扫描的路径:");
String rootDirPath = scanner.next();
System.out.println("请输入要查询的关键字:");
String word = scanner.next();
File file = new File(rootDirPath);
if(!file.isDirectory()){
System.out.println("输入的路径非法~");
return;
}
//2.递归的进行遍历
scanDir(file,word);
}
private static void scanDir(File file, String word) throws IOException {
//1.先列出file中都有哪些内容
File[] files = file.listFiles();
if(files == null){
return;
}
//2.遍历每个元素,针对普通文件和目录分别进行处理
for (File f: files) {
if(f.isFile()){
//针对文件进行内容查找
if(containsWord(f,word)){
System.out.println(f.getCanonicalPath());
}
}else if(f.isDirectory()){
//进行递归操作
scanDir(f,word);
}
}
}
private static boolean containsWord(File f, String word) {
StringBuilder sb = new StringBuilder();
//把f中的内容都读出来,放到一个StringBuilder中
try (Reader reader = new FileReader(f)){
char[] buffer = new char[1024];
while (true){
int len = reader.read(buffer);
if(len == -1){
break;
}
//把这一段读到的结果,放到StringBuilder中
sb.append(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
//indexOf返回的是子串的下标,如果word在StringBuilder中不存在,则返回下标为-1
return sb.indexOf(word) != -1;
}
}