
目录
文件的含义(狭义):在Java中,我们一般谈到文件,都是指一个存储在磁盘上的文件。
文件的含义(广义):抛开Java,站在系统的角度来看,操作系统在管理很多软件资源和硬件设备的时候,把这些东西抽象成了一个一个的文件。(显示器/键盘/网卡……抽象成文件)这就是系统中典型的"一切皆文件"思想。
狭义文件可以分成两个大类:
1、普通文件
2、目录文件(文件夹,就是打开这个目录文件,里面还有许多文件)
广义文件:
在Java中为了方便我们操作文件,标准库给出了一个File类,因此我们可以通过Fire类来进行操作。
构造方法:
- File(File parent, String child) //根据父目录 + 孩子文件路径,创建一个新的 File 实例
- File(String pathname) //根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
- File(String parent, String child) //根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用//路径表示
我们比较常用的是第二种:
File(String pathname) //根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
这里给File传递一个具体的路径,通过路径来指定唯一的一个文件(普通文件或者目录文件)
比如:
File file=new File("D:/test.txt");
这里通过 \ 或者 / 来分隔不同层级的目录,一般我们会比较偏向使用 / ,防止 \ +其他字符被当成转义字符。
绝对路径和相对路径
绝对路径:D:\idea project\lianxi\test\src,以一个盘符开头的路径(比如这里的D:就是盘符)。
相对路径:一般以. 或者.. 开头,以工作目录为基准,去找相对应的路径。如果以D:\idea project\lianxi\test\src为基准目录,此时要表示src中的FileDemo1.java,相对路径就可以写作 .\FileDemo1.java,此时.就表示当前的基准目录D:\idea project\lianxi\test\src。
基准目录:D:\idea project\lianxi\test\src
表示src中的FileDemo1.java
相对路径:.\FileDemo1.java
基准目录:D:\idea project\lianxi\test\src\test.java
表示src中的FileDemo1.java
相对路径:..\FileDemo1.java(..表示当前目录的上级目录)
- public static void main(String[] args) throws IOException {
- // 这种既没有盘符, 也没有 ./ 和 ../ 的, 这个也是相对路径
- // 相当于省略了 ./
- File file = new File("helloworld.txt");
- //因为此时没有这个文件,我们无法打开,所以我们需要创建这个文件
- file.createNewFile();
- //判断此文件是否存在
- System.out.println(file.exists());
- //判断是否是文件
- System.out.println(file.isFile());
- //判断是否是目录文件
- System.out.println(file.isDirectory());
- //删除文件
- System.out.println(file.delete());
- }
throws IOException
在一些访问IO操作的时候,比如读写文件,操作文件都有可能涉及到这个异常,这个异常是一个受查异常,在使用的时候一定要显示处理,可以使用throws或者try catch来显示捕获。
创建文件时为什么会抛异常?
1、没有权限
2、磁盘空间不够
文件系统中的权限,典型的就是读和写,会针对不同的用户,给与不同的权限。
- 返回值类型
- String getParent() 返回 File 对象的父目录文件路径
-
- String getName() 返回 File 对象的纯文件名称
-
- 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() 判断用户是否对文件有可写权限
多级目录的创建:
- public static void main(String[] args) {
- File file = new File("test/aaa/bbb");
- System.out.println(file.exists());
- // mk 就是 make . dir 就是 direction 单词的缩写.
- // mkdir 不支持创建多级目录. 但是 mkdirs 能支持.
- file.mkdirs();
- System.out.println(file.exists());
- System.out.println(file.isDirectory());
- }
移动文件:
- public static void main(String[] args) {
- File file = new File("./test.txt");
- File file2 = new File("./out/test.txt");
- file.renameTo(file2);
- }
renameTo除了可以移动文件位置之外,还可以更改文件名。所谓的文件移动(剪切粘贴),对于操作系统而言,每个文件都有自己的属性,这个属性就是文件的路径,移动操作其实就是修改文件的属性。

file. deleteOnExit(),主要用于一些"临时文件",意思就是这个临时文件关闭之后就自动删除了。
就比如我们使用word的时候,打开文件的时候,系统会自动生成一个临时的隐藏文件,如果此时电脑突然掉电,此时临时文件来不及删除,下次启动的时候,office就会自动监测到当前的临时文件存在,于是就能知道上次是异常结束,就会提示用户是否要恢复数据。
面试题:给你一个list方法,如何遍历一个目录中所有的文件?
首先我们来看看list怎么使用?

代码实现:
- public class FileDemo4 {
- //通过递归的方式,来罗列出制定目录中所有的文件路径
- public static List
result=new ArrayList<>(); - public static void main(String[] args) {
- getAllFiles(".");
- for (String s : result) {
- System.out.println(s);
- }
- }
- public static void getAllFiles(String basePath){
- File file=new File(basePath);
- //如果是普通文件,就直接添加到result中
- if(file.isFile()){
- result.add(basePath);
- //如果是目录文件,则递归,添加每个子目录中的文件
- }else if(file.isDirectory()){
- String[] files=file.list();
- for(String f:files){
- getAllFiles(basePath+"/"+f);
- }
- }
- }
- }
InputStream/FileInputStream:文件读取操作,按照字节为单位进行读文件
代码示例:
- public static void main(String[] args) {
- InputStream inputStream=null;
- try {
- inputStream =new FileInputStream("./test.txt");
- while(true){
- //逐个字节的方式把文件内容读取出来,每次调用read就可以读取一些数据出来
- //read的无参版本就是一次读取一个字节
- //read返回值就是这次操作读到的字节,这个结果的范围是0-255
- //如果读到文件末尾(EOF,end of file),此时继续read,就会返回-1
- int b=inputStream.read();
- if(b==-1){
- //读取完成
- break;
- }
- System.out.printf("%c",b);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }finally {
- try{
- //用完记得关闭,防止资源泄露
- inputStream.close();
- }catch(IOException e){
- e.printStackTrace();
- }
- }
- }
此时我们这里使用try catch来捕获异常,同时使用finally来关闭文件(使用流对象,读写文件之后,一定要记得关闭,如果没有关闭,就可能造成资源泄露),但是可以发现finally里面还包含一个try catch,看起来比较繁琐,此时我们使用try with resources语法,可以更好解决这个问题
- public static void main(String[] args) {
- try(InputStream inputStream=new FileInputStream("./test.txt")){
- while(true){
- int b=inputStream.read();
- if(b==-1){
- break;
- }
- System.out.printf("%c",b);
- }
- }catch(IOException e){
- e.printStackTrace();
- }
- }
把文件的打开放try()里面,try catch执行完毕之后,会自动将文件关闭 。
带参数的read:
- public static void main(String[] args) {
- try (InputStream inputStream = new FileInputStream("./test.txt")) {
- //一次读取1024个字节
- byte[] buffer = new byte[1024];
- while (true) {
- int len = inputStream.read(buffer);
- if (len == -1) {
- break;
- }
- //中文和英文的编码方式不同,英文直接就是ASCII码,中文就需要使用UTF-8或者GBK
- //一个汉字在UTF-8中,是由3个字节构成的
- for (int i = 0; i < len; i += 3) {
- String s = new String(buffer, i, 3, "UTF-8");
- System.out.print(s);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
这里不仅可以用read来读取文件,也可以用Scanner,Scanner内部持有的InputStream是标准输入,标准输入的这个文件,一般是不关闭的,这个文件是每个进程创建出来之后,操作系统默认打开的文件。
- public static void main(String[] args) {
- // 尝试从文件中读取出中文. 借助标准库中内置的处理字符集的方式.
- // Scanner 不光能从控制台读取标准输入, 也可以从文件中读取数据.
- try (InputStream inputStream = new FileInputStream("./test.txt")) {
- // Scanner 里面也有个 close 方法, 这个 close 其实也就是用来关闭 Scanner 内包含的 InputStream
- try (Scanner scanner = new Scanner(inputStream, "UTF-8")) {
- while (scanner.hasNext()) {
- String s = scanner.next();
- System.out.print(s);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
OutputStream/FileOutputStream:文件写入操作,按照字节为单位进行写文件。
例如:按照字节写入:
- public static void main(String[] args) {
- // 一旦按照 OutputStream 的方式打开文件, 就会把文件的原来的内容给清空掉.
- try (OutputStream outputStream = new FileOutputStream("./test.txt")){
- // 写入一个字符
- // outputStream.write('x');
- // 按照字节来写入
- byte[] buffer = new byte[] {
- (byte)'a', (byte)'b', (byte)'c', (byte)'d'
- };
- outputStream.write(buffer);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
按照字符串写入:
- public static void main(String[] args) {
- // 一旦按照 OutputStream 的方式打开文件, 就会把文件的原来的内容给清空掉.
- try (OutputStream outputStream = new FileOutputStream("./test.txt")){
- // 按照字符串来写入
- String s = "hello world";
- outputStream.write(s.getBytes());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
包装之后写入:
- public static void main(String[] args) {
- // 使用 PrintWriter 类来包装一下 OutputStream 然后可以更方便的进行写数据.
- try (OutputStream outputStream = new FileOutputStream("./test.txt")) {
- // 使用 PrintWriter 类来包装一下
- try (PrintWriter writer = new PrintWriter(outputStream)) {
- writer.println("你好世界");
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
以上几种写入都会覆盖原有内容,以下不会覆盖
- public static void main(String[] args) {
- String content="你好,世界";
- try(FileWriter fileWriter=new FileWriter("test.txt",true)){
- fileWriter.write(content);
- }catch (IOException e){
- e.printStackTrace();
- }
- }
就是第二个参数写成true,这个参数代表是否覆盖原有内容,默认为false。
刷新缓冲区:flush()
计算机读写内存的速度比读写磁盘的速度快的多,所以有些时候为了提高效率,可以使用缓冲区,可以减少直接访问磁盘的次数。
缓冲区其实就是一段内存空间(这个内存是OutputStream里面自带的),当我们使用write方法来写数据的时候,并不是直接把数据写入磁盘,而是先放到缓冲区中,如果缓冲区满了,或者手动调用flush,才会真的把数据写到磁盘上。(内存和磁盘之间的缓冲区,往往是一个内存空间)
1、指定一个目录,扫描这个目录,找到文件名中包含了指定字符的文件,并提示用户是否要删除这个文件,根据用户的输入决定是否要删除
- public static void main(String[] args) throws IOException {
- //1、输入待扫描的目录和查询关键词
- System.out.println("请输入需要扫描的根目录(绝对路径");
- Scanner scanner=new Scanner(System.in);
- String root=scanner.next();
- File rootDir=new File(root);
- if(!rootDir.isDirectory()){
- System.out.println("您输入的路径错误!程序直接退出");
- return;
- }
- System.out.println("请输入要查找的文件名中包含的关键词");
- String token=scanner.next();
- //2、递归遍历目录
- //result表示递归的结果,就包含带着所有token关键词的文件名
- List
result=new ArrayList<>(); - scanDir(rootDir,token,result);
-
- //3、遍历result,问用户是否要删除
- for(File f:result){
- System.out.println(f.getCanonicalPath()+" 是否要删除(Y/N)");
- String input=scanner.next();
- if(input.equals("Y")){
- f.delete();
- }
- }
- }
-
- private static void scanDir(File rootDir, String token, List
result) throws IOException { - File[] files=rootDir.listFiles();
- //list返回的是一个文件名(String),使用listFiles直接返回File对象
- if(files==null || files.length==0){
- return;
- }
- for(File f:files){
- if(f.isDirectory()){
- scanDir(f,token,result);
- }else{
- if(f.getName().contains(token)){
- result.add(f.getCanonicalFile());
- }
- }
- }
- }
2、复制一个文件,启动程序之后,让用户输入一个文件的路径(绝对路径),要求这个文件是一个普通文件(不是目录文件),然后在指定一个要复制过去的目标目录
- public static void main(String[] args) {
- //进行文件复制
- Scanner scanner=new Scanner(System.in);
- System.out.println("请输入需要复制的文件(绝对路径):");
- String srcPath= scanner.next();
- //打开此文件
- File srcFile=new File(srcPath);
- if(!srcFile.isFile()){
- System.out.println("文件路径错误!程序直接退出");
- return;
- }
- System.out.println("请输入要复制到的目标路径(绝对路径):");
- String destPath=scanner.next();
- File destFile=new File(destPath);
- //如果destFile已经存在,就不进行复制
- if(destFile.exists()){
- System.out.println("目标文件的路径已经存在!程序直接退出");
- return;
- }
- if(!destFile.getParentFile().exists()){
- //如果目标文件的父级目录不存在,也提示报错
- System.out.println("目标文件的父目录不存在!程序直接退出");
- return;
- }
- //具体进行复制操作
- //打开需要复制的文件,按字节读取,目标文件按字节写入
- try(InputStream inputStream=new FileInputStream(srcFile)){
- OutputStream outputStream=new FileOutputStream(destFile);
- while(true){
- byte[] buffer=new byte[1024];
- int len=inputStream.read(buffer);
- if(len==-1){
- break;
- }
- outputStream.write(buffer,0,len);
- }
- //加flush触发close(其实这里不加也能触发,加了比较好)
- outputStream.flush();
- }catch (IOException e){
- e.printStackTrace();
- }
- }
什么样的类可以放进try()中呢?实现Closeable接口的类。
3、在指定目录中按照文件内容查找,看看是否包含匹配的结果
- public static void main(String[] args) throws IOException {
- Scanner scanner=new Scanner(System.in);
- //1、输入一个代搜索的路径
- System.out.println("请输入要扫描的根目录:");
- String rootDir=scanner.next();
- File rootFile=new File(rootDir);
- if(!rootFile.isDirectory()){
- System.out.println("该目录不存在或者不是文件!程序直接退出");
- return;
- }
- //2、输入查询词
- System.out.println("请输入要查询的词:");
- String query=scanner.next();
- //3、遍历目录以及文件,进行匹配
- List
result=new ArrayList<>(); - scanDirWithContent(rootFile,query,result);
- //4、把结果打印出来
- for(File f:result){
- System.out.println(f.getCanonicalPath());
- }
- }
-
- private static void scanDirWithContent(File rootFile, String query, List
result) { - File[] files=rootFile.listFiles();
- if(files==null || files.length==0){
- return;
- }
- for(File f:files){
- if(f.isDirectory()){
- scanDirWithContent(f,query,result);
- }else{
- if(f.getName().contains(query)){
- //看看文件名称中是否包含
- result.add(f);
- //看看文件内容是否包含
- }else if(isContentContains(f, query)){
- result.add(f);
- }
-
- }
- }
- }
-
- private static boolean isContentContains(File f, String query) {
- //打开f这个文件,依次读取每一行结果,去和query匹配(indexOf)
- StringBuilder stringBuilder=new StringBuilder();
- try(InputStream inputStream=new FileInputStream(f)){
- Scanner scanner=new Scanner(inputStream,"UTF-8");
- while(scanner.hasNextLine()){
- String line=scanner.nextLine();
- stringBuilder.append(line+"\n");
- }
- }catch (IOException e){
- e.printStackTrace();
- }
- //只要结果不等于-1,就说明查到了
- return stringBuilder.indexOf(query)!=-1;
- }
以上就是今天的内容,有什么问题都可以在评论区留言🍉🍉🍉
