好久不见啦~
目录
1.文件
我们常说的文件是存储在硬盘上的普通文件。(本节内容主要是针对普通文件进行讨论)
1.1普通文件
形如txt,jpg,mp3等存储在硬盘上的文件,被称为普通文件。
1.1.1硬盘
①机械硬盘:
a.机械硬盘的基本构造:(下面这是一张机械硬盘的简介图)
磁盘(盘片):存储数据的介质
磁头和电机:执行部分
电路板:控制部分
b.运行原理:
当机械硬盘一旦通电,里面的盘片就会高速运转,此时磁头就在盘面上找相对应的数据。但是由于机械硬盘的硬件结构是有限的,盘片转速越高,读写速度就越快,而易知盘片的速度不可能永无止境地高,所以已经有10年停滞不前了。所以引入了下面我们要谈及的固态硬盘
②固态硬盘(SSD):
这就是一个固态硬盘。
固态硬盘的硬件结构和机械硬盘截然不同,固态硬盘的读写速度要比机械硬盘快上太多。
而我们现在主要讨论的是机械硬盘。
1.2目录文件
1.2.1结构
在计算机里,保管储存文件是通过操作系统中的“文件系统”来实现的。
而文件系统中一般是通过树形结构来组织磁盘上的目录和文件的,就是一颗N叉数
给大家举个图例看看:
这就是我们所说的树结构
1.2.2路径
①绝对路径:
绝对路径指的就是一个具体的路径,以盘符开头的。比如:C:\Program Files\Java
②相对路径:
以.或者..开头的,其中.表示当前路径
..表示当前路径的父目录(上级路径)
相对路径就必须要有一个基准目录,相对路径就是从基准目录出发,按照基准路径出发来找到相对应的文件
比如:此时的基准路径为:C:\Program Files\Java。而此时我要找javac.exe。
./javac.exe就是以上所需。. 就代表当前的基准路径。
而要找到src.zip就可以这样写../src.zip。.. 就相当于回到了基准的上一层路径(C:\Program Files),再来找目标路径。
用通俗一点的话来解释就是,绝对路径是相对于事务的整体而言的,而相对问题是相对于事务的局部而言的。
1.3文件的分类
①文本文件:
文件存储的是字符(本质上也是存储的字节,只是相邻字节刚好构成了一个个字符)。平时中类似于.txt,.c,.java这种都是文本文件。
②二进制文件:
文件存储的是字节。类似于.class,.jpg,.doc都是二进制文件
③如何区分二进制文件和文本文件:
最简单的方式是用记事本打开,如果是乱码,即是二进制文件,反之则是文本文件。
2.java中的操作文件
2.1文件系统的相关操作
是指通过文件资源管理器能够完成的一些功能,在Java中提供了File类,通过这个类来完成一系列操作,下面我们将着重讲解。
2.2.1File类的介绍
①File的构造方法:
File的构造方法,能够传入一个路径来指定一个文件,这个路径可以是绝对路径也可以是相对路径
②File的一些方法:
③我们针对其中的某些方法来进行操作演示:
代码:
import java.io.File; import java.io.IOException; public class demo1 { public static void main(String[] args) throws IOException { File f=new File("C:/ProgramData/test.txt"); System.out.println("获取到文件的父目录:"+f.getParent()); System.out.println("获取到文件名:"+f.getName()); System.out.println("获取到文件路径:"+f.getPath()); System.out.println("获取到文件的绝对路径:"+f.getAbsolutePath()); //这里需要抛出一个异常,并且这里是化简过的绝对路径 System.out.println("获取到文件的绝对路径:"+f.getCanonicalPath()); System.out.println("==============="); //这里的路径是一个基准路径 File f1=new File("./ProgramData/test.txt"); System.out.println("获取到文件的父目录:"+f1.getParent()); System.out.println("获取到文件名:"+f1.getName()); System.out.println("获取到文件路径:"+f1.getPath()); System.out.println("获取到文件的绝对路径:"+f1.getAbsolutePath()); //这里需要抛出一个异常,并且这里是化简过的绝对路径 System.out.println("获取到文件的绝对路径:"+f1.getCanonicalPath()); } }
对代码中的部分内容来进行说明:
2.2.2列出文件
代码:
import java.io.File; import java.util.Arrays; public class demo2 { public static void main(String[] args) { File f = new File("./"); //查看此目录下的内容(列出目录内容) System.out.println(Arrays.toString(f.list())); //按照file对象的方法打印 System.out.println(Arrays.toString(f.listFiles())); } }
结果:
2.2.3创建文件
代码:
import java.io.File; import java.io.IOException; public class demo2 { public static void main(String[] args) throws IOException { //创建一个文件 File f=new File("./test.txt"); //判断文件是否存在 System.out.println(f.exists()); //创建文件 f.createNewFile(); //文件创建结束,判断是否存在 System.out.println(f.exists()); } }
输出结果:
2.2.4创建目录
①创建一个目录:
代码:
import java.io.File; import java.io.IOException; public class demo2 { public static void main(String[] args) throws IOException { //创建一个文件 File f=new File("./aa"); //创建一个目录 f.mkdir(); } }
结果:
②创建多个目录
代码:
import java.io.File; import java.io.IOException; public class demo2 { public static void main(String[] args) throws IOException { //创建一个文件 File f=new File("./aa/bb/cc"); //创建一个目录 f.mkdirs(); } }
结果:
2.2.5删除文件
代码:
import java.io.File; import java.io.IOException; public class demo2 { public static void main(String[] args) throws IOException { //创建一个文件 File f=new File("./test.txt"); //判断文件是否存在 System.out.println(f.exists()); //删除文件 f.delete(); //删除文件后是否存在 System.out.println(f.exists()); } }
操作结果:
2.2文件内容的相关操作
针对文件内容的读写,Java标准库提供了一组类,按照文件的内容,分成了两个系列:
①字节流对象,针对二进制文件,以字节为单位进行读写的
读:InputStream 写:OutputStream
②字符流对象,针对文本文件,是以字符为单位进行读写的
读:Reader 写:Writer
注意!!!上面这四类均是抽象类,若是我们想要实现的话需要用它们的子类
FileInputStream,FileOutputStream,FileReader,FileWriter。
这一组都是特指针对普通文件进行读写的
2.2.1打开文件
实例化对象的同时,输入指定路径,这里不详说,在代码中有体现
2.2.2读文件
①InputStream和Reader均是通过read方法来读取文件,我们首先讲一下read方法:
a.无参数版本:
一次读一个字节,返回值是读到的这个字节(注意!当读到-1时,表示本文件已被读完)
b.一个参数版本:一次读若干个字节,把读到的结果放到指定的数组中,返回值就是读到的字节数
c.三个参数版本:一次读若干个字节,把读的结果放到参数中指定的数组中,返回值就是读到的字节数。注意!!!这里不是从数组的起始位置来对元素进行放置,而是从中间位置放置(off下标),len表示最多能放多少个元素
②通过inputStream来读取文件
a.一次读一个字节
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class demo2 { public static void main(String[] args) { InputStream inputStream = null; try {//创建对象,也是打开文件,有可能没有文件,因此需要抛异常 inputStream = new FileInputStream("C:/Users/张洋洋的小布偶/Desktop/test.txt");//需要指定路径,可以是相对路径也可以是绝对路径,也可以是File对象 //尝试一个一个字节的读,把整个文件读完 while(true){ int x = inputStream.read(); if(x == -1){ break;//表示读完了所有的字节 } System.out.println(x);//打印 } } catch (IOException e) { //这个包含了FileNotFoundException(子类),因此可以合并,IO操作失败的可能性是非常大的 e.printStackTrace(); }finally { //读完之后需要关闭文件,释放资源 try { inputStream.close();//这个放在finally里面更好有需要把定义放到外面去 } catch (IOException e) { e.printStackTrace(); } } } }
(我们可以发现要关闭文件就要用finally,这是相当麻烦的,但与此同时,java提供了一个方法try,就可以在读取完try之后自动关闭,下面我们会进行演示)
b.一次读多个字节
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class demo2 { public static void main(String[] args) { try (InputStream inputStream = new FileInputStream("C:\\Users\\张洋洋的小布偶\\Desktop/test.txt")) { while (true) { byte[] tmp = new byte[1024]; int x = inputStream.read(tmp); if (x == -1) { break;//表示读完了所有的字节 } for (int i = 0; i < x; i++) { //打印 System.out.println(tmp[i]); } } } catch (IOException e) { e.printStackTrace(); } } }
结果如下:
③通过Reader来读取文件
import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class demo2 { public static void main(String[] args) { try(Reader reader = new FileReader("C:\\Users\\张洋洋的小布偶\\Desktop/test.txt")) { while (true){ char[] c = new char[1024]; int x = reader.read(c);//一次读多个 if(x == -1){ break; } /*for (int i = 0; i < x; i++) { System.out.println(c[i]); }*/ String s = new String(c,0,x);//如果传入的是byte也可以指定字符编码 System.out.println(s);//这样也可以读 } } catch (IOException e) { e.printStackTrace(); } } }
结果如下:
2.2.3写文件
①OutputStream
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class demo2 { public static void main(String[] args) { try (OutputStream outputStream = new FileOutputStream("C:\\Users\\张洋洋的小布偶\\Desktop/test.txt")) { /*outputStream.write(98); outputStream.write(97);一次写一个 outputStream.write(97);*/ //也可以一次写多个 byte[] b = new byte[]{98,97,97}; outputStream.write(b);//一次写多个 这里的写操作每次按照写方式打开文件,都会清空原有的文件的内容,然后再从起始位置往后写 } catch (IOException e) { e.printStackTrace(); } } }
结果如下:
②Writer
import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class demo2 { public static void main(String[] args) { try(Writer writer = new FileWriter("C:\\Users\\张洋洋的小布偶\\Desktop/test.txt")){ writer.write("aaa");//写操作 } catch (IOException e) { e.printStackTrace(); } } }
结果如下:
2.2.4关闭文件
每次读完后需要关闭文件,释放资源
3.文件操作的三个案例
3.1查找文件并删除
①思想:递归
②代码:
import java.io.File; import java.io.IOException; import java.util.Scanner; //实现查找文件并删除文件 public class Demo13 { public static void main(String[] args) { //先输入要扫描的目录,以及要删除的文件名 Scanner input = new Scanner(System.in); System.out.println("请输入要扫描的路径:"); String rootDirPath = input.next(); System.out.println("请输入要删除的文件名:"); String toDeleteName = input.next(); File rootDir = new File(rootDirPath);//构建文件对象 if(!rootDir.isDirectory()){ //不是一个目录 System.out.println("你输入的路径有误"); return;//可以抛一个异常 } //遍历这个目录,寻找要删除的文件 scanDir(rootDir,toDeleteName); } public static void scanDir(File rootDir,String toDeleteName){ File[] files = rootDir.listFiles(); if(files == null){ //rootDir是空目录,返回 return; } //不是空目录就遍历此目录里面的所有内容,如果是普通文件就看是不是要删除的文件,不是文件是目录的话,就再遍历这个目录 for(File f : files){//列出rootDir里面有什么内容 if(!f.isFile()){ scanDir(f,toDeleteName); } if(f.isFile()){ if(f.getName().contains(toDeleteName)){ //不要求名字完全一样,只要文件名中包含了关键字就可以删除 //进行删除操作 deleteFile(f); } } } } public static void deleteFile(File f){ try { System.out.println(f.getCanonicalPath() + "确认要删除文件吗(Y/N)"); Scanner input = new Scanner(System.in); String chose = input.next(); if(chose.equals("Y") || chose.equals("y")){ f.delete();//进行删除 System.out.println("文件删除成功"); }else{ System.out.println("文件放弃删除"); } } catch (IOException e) { e.printStackTrace(); } } }
3.2普通文件的复制
①找到文件再进行复制
②代码:
import java.io.*; import java.util.Scanner; //文件复制,需要让用户支出两个文件路径,一个是原路径(被复制的文件),另一个是目标路径(复制后生成的文件) public class Demo14 { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("请输入要拷贝的源路径:"); String str = input.next(); System.out.println("请输入要拷贝的目标路径:"); String sub = input.next(); File file = new File(str); if(!file.isFile()){//需要判断是不是正确的路径,目标路径不需要判断,因为没有的话,是会自己创建的 System.out.println("不是一个正确的源路径"); return; } //将源文件里面的内容读出来,然后再用写操作写到目标文件中去 try(InputStream inputStream = new FileInputStream(str)) { try(OutputStream outputStream = new FileOutputStream(sub)) { byte[] b = new byte[1024]; while(true){ int x = inputStream.read(b); if(x == -1){ break; } outputStream.write(b,0,x);//需要指定长度,不能把所有的b都放进去 } } } catch (IOException e) { e.printStackTrace(); } } }
3.3文件内容的查找
①思想:递归
②代码:
import java.io.*; import java.util.Scanner; //进行文件内容的查找,扫描指定目录,找到名称或内容中包含指定字符的所有普通文件(不包含目录) public class Demo15 { public static void main(String[] args) throws IOException { Scanner input = new Scanner(System.in); System.out.println("请输入要扫描的文件路径:"); String rootDirPath = input.next(); System.out.println("请输入要查询的关键字:"); String word = input.next(); File rootDir = new File(rootDirPath); if(!rootDir.isDirectory()){ System.out.println("输入的路径非法!"); return; } sDir(rootDir,word); } private static void sDir(File rootDir, String word) throws IOException { File[] files = rootDir.listFiles(); if(files == null){ return; } for (File f:files) { if(f.isDirectory()){ sDir(f,word); } if(f.isFile()){ //针对文件进行查找 if(containsWord(f,word)){ System.out.println(f.getCanonicalPath()); } } } } private static boolean containsWord(File f, String word) { StringBuilder stringBuilder = new StringBuilder(); //把f中的内容都读出来,放到StringBuilder中,看是否包含关键字 try(Reader reader = new FileReader(f)){ char[] c = new char[1024]; while(true){ int x = reader.read(c); if(x == -1){ break; } stringBuilder.append(c,0,x); } } catch (IOException e) { e.printStackTrace(); } //indexOf返回的是子串的下标,如果word存在,那么下标一定不是-1, return stringBuilder.indexOf(word) != -1; } }