【 Java 中操作文件 】

一、File 概述

Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述.注意,有 File 对象,并不代表真实存在该文件

1.1 属性

在这里插入图片描述

1.2 构造方法

在这里插入图片描述

注意:

提到相对路径就需要一基准路径.当new一个File对象时如 File file = new File(“./test.txt”);此时它的基准路径是啥呢?如果是通过IDEA来运行程序,此时基准路径就是当前java项目所在的路径,如

在这里插入图片描述

1.3 方法

在这里插入图片描述

1.4 案例

  1. 观察 get 系列的特点和差异
import java.io.File;
        import java.io.IOException;
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("..\\hello-world.txt"); // 并不要求该文件真实存在
        System.out.println(file.getParent());
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getCanonicalPath());
    }
}
  1. 普通文件的创建、删除
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("hello-world.txt"); // 要求该文件不存在,才能看到相同的现象
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.createNewFile());
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.createNewFile());
    }
}

注意:

使用 createNewFile() 方法时,若该文件不存在就在此直接创建一个空的文件然后返回true,若已经存在该文件就直接返回false.

创建前,没有该文件
在这里插入图片描述

创建后
在这里插入图片描述

  1. 普通文件的删除
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("some-file.txt"); // 要求该文件不存在,才能看到相同的现象
        System.out.println(file.exists());
        System.out.println(file.createNewFile());
        System.out.println(file.exists());
        System.out.println(file.delete());
        System.out.println(file.exists());
    }
}
  1. 观察目录的创建
public class Main {
    public static void main(String[] args) throws IOException {
        File dir = new File("some-dir"); // 要求该目录不存在,才能看到相同的现象
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
        System.out.println(dir.mkdir());
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
    }
}
  1. 观察目录创建2
public class Main {
    public static void main(String[] args) throws IOException {
        File dir = new File("some-parent\\some-dir"); // some-parent 和 somedir 都不存在
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
        System.out.println(dir.mkdirs());
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
    }
}

注意: mkdir() 的时候,如果中间目录不存在,则无法创建成功; mkdirs() 可以解决这个问题.即要想创建多级目录就要使用 mkdirs()

  1. 观察文件重命名
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("some-file.txt"); // 要求 some-file.txt 得存在,可以是普通文件,可以是目录
        File dest = new File("dest.txt"); // 要求 dest.txt 不存在
        System.out.println(file.exists());
        System.out.println(dest.exists());
        System.out.println(file.renameTo(dest));
        System.out.println(file.exists());
        System.out.println(dest.exists());
    }
}

二、文件内容的读写 —— 数据流

在这里插入图片描述

在这里插入图片描述

2.1 InputStream 概述

在这里插入图片描述

说明:

InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用 FileInputStream

2.1.1 FileInputStream 概述

构造方法:

在这里插入图片描述

2.1.1.1 如何按字节进行数据读

代码示例:

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        //指定打开文件的路径,此处可以是绝对路径也可以是相对路径,还可以是File对象
        //try 会帮我们自动调用close方法,但是条件是要实现Closeable接口.所有刘对象都实现了
        try (InputStream is = new FileInputStream("hello.txt")) {
            byte[] buf = new byte[1024];
            int len;
            while (true) {
                //把读的结果放入到指定参数数组中,并返回读到的字节数
                len = is.read(buf);
                if (len == -1) {
                    //代表文件已经全部读完
                    break;
                }
                for (int i = 0; i < len; i++) {
                    System.out.printf("%c", buf[i]);
                }
            }
        }
        catch(IOException e){
             e.printStackTrace();
        }
              //finally{
             // 关闭文件资源
            // is.close;}
    }
}

注意:

  1. 此方法 IO 次数更少,性能更好.
  2. 为何这里 len == -1 的时候就表示结束,还需要观察 read 方法的源码!!
  3. 上述代码不需要在 finally 里面调用close方法来关闭文件资源,try语句里面会自动帮我们调用.但前提是要实现Closeable接口,所有的流对象都实现了该接口

2.1.2 利用 Scanner 进行字符读取

先举个例子:

把文件内容中填充中文看看,注意,写中文的时候使用 UTF-8 编码。hello.txt 中填写 “你好中
国”

// 需要先在项目目录下准备好一个 hello.txt 的文件,里面填充 "你好中国" 的内容
public class Main {
    public static void main(String[] args) throws IOException {
        try (InputStream is = new FileInputStream("hello.txt")) {
            byte[] buf = new byte[1024];
            int len;
            while (true) {
                len = is.read(buf);
                if (len == -1) {
                    // 代表文件已经全部读完
                    break;
                }
                   // 每次使用 3 字节进行 utf-8 解码,得到中文字符
                   // 利用 String 中的构造方法完成
                   // 这个方法了解下即可,不是通用的解决办法
                for (int i = 0; i < len; i += 3) {
                    String s = new String(buf, i, 3, "UTF-8");
                    System.out.printf("%s", s);
                }
            }
        }
    }
}

注意: 这里我利用了这几个中文的 UTF-8 编码后长度刚好是 3 个字节和长度不超过 1024 字节的现状,但这种方式并不是通用的


上述例子中,我们看到了对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,所以,我们使用一种我们之前比较熟悉的类来完成该工作,就是 Scanner 类

在这里插入图片描述

代码示例:

public class Main {
    public static void main(String[] args) throws IOException {
        try (InputStream is = new FileInputStream("hello.txt")) {
            try (Scanner scanner = new Scanner(is, "UTF-8")) {
                while (scanner.hasNext()) {
                    String s = scanner.next();
                    System.out.print(s);
                }
            }
        }
    }
}

除此之外,我们还可以通过 Reader 类的 read 方法来进行字符读取


2.2 OutputStream 概述

方法:

在这里插入图片描述

说明:

OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中,所以使用 FileOutputStream

2.2.1 如何按字节进行数据写

try (OutputStream os = ...) {
        byte[] buf = new byte[1024];
        while (/* 还有未完成的业务数据 */) {
        // 将业务数据填入 buf 中,长度为 n
        int n = ...;
        os.write(buf, 0, n);
        }
        os.flush(); // 进行数据刷新操作
   }

2.2.2 利用 OutputStreamWriter 进行字符写入

不推荐做法示例:

public class Main {
    public static void main(String[] args) throws IOException {
        try (OutputStream os = new FileOutputStream("output.txt")) {
            String s = "Nothing";
            byte[] b = s.getBytes();
            os.write(b);
            // 不要忘记 flush
            os.flush();
        }
    }
}

利用 PrintWriter 找到我们熟悉的方法

上述,我们其实已经完成输出工作,但总是有所不方便,我们接来下将 OutputStream 处理下,使用PrintWriter 类来完成输出,因为PrintWriter 类中提供了我们熟悉的 print/println/printf 方法

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        try (OutputStream os = new FileOutputStream("output.txt")) {
                // 告诉它,我们的字符集编码是 utf-8 的
            try (OutputStreamWriter osWriter = new OutputStreamWriter(os, "UTF-8"){
                try (PrintWriter writer = new PrintWriter(osWriter)) {
                // 接下来我们就可以方便的使用 writer 提供的各种方法了
                writer.println("我是第一行");
                writer.print("我的第二行\r\n");
                writer.printf("%d: 我的第三行\r\n", 1 + 1);
                writer.flush();
            }
        }
    }
}

注意上述代码含义:

在这里插入图片描述

注意:除此之外,我们还可以通过 Writer 类的 write 方法来进行字符写入


三、文件操作案例

3.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 toDeleteName = scanner.next();
        File rootDir = new File(rootDirPath);
        if (!rootDir.isDirectory()) {
            System.out.println("输入的扫描路径有误!");
            return;
        }
        // 2. 遍历目录, 把 指定目录 中的所有文件和子目录都遍历一遍, 从而找到要删除的文件
        //    通过这个方法来实现递归遍历并删除的操作
        scanDir(rootDir, toDeleteName);
    }

    private static void scanDir(File rootDir, String toDeleteName) {
        // 1. 先列出 rootDir 中都有哪些内容
        File[] files = rootDir.listFiles();
        if (files == null) {
            // rootDir 是一个空目录
            return;
        }
        // 2. 遍历当前列出的这些内容. 如果是普通文件, 就检测文件名是否是要删除的文件.
        //    如果是目录, 就递归的进行遍历
        for (File f : files) {
            if (f.isFile()) {
                // 普通文件的情况
                if (f.getName().contains(toDeleteName)) {
                    // 不要求名字完全一样, 只要文件名中包含了关键字即可删除
                    // 就进行删除操作
                    deleteFile(f);
                }
            } else if (f.isDirectory()) {
                // 目录就递归的进行遍历
                scanDir(f, toDeleteName);
            }
        }
    }

    private static void deleteFile(File f) {
        try {
            System.out.println(f.getCanonicalPath() + " 确认要删除吗? (Y/n)");
            Scanner scanner = new Scanner(System.in);
            String choice = scanner.next();
            if (choice.equals("Y") || choice.equals("y")) {
                f.delete();
                System.out.println("文件删除成功!");
            } else {
                System.out.println("文件取消删除!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.2 复制文件

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();
        }
    }
}

3.3 查找文件

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 rootDir = new File(rootDirPath);
        if (!rootDir.isDirectory()) {
            System.out.println("输入的路径非法!");
            return;
        }
        // 2. 递归的进行遍历
        scanDir(rootDir, word);
    }

    private static void scanDir(File rootDir, String word) throws IOException {
        // 1. 先列出 rootDir 中都有哪些内容
        File[] files = rootDir.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 stringBuilder = 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 中
                stringBuilder.append(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // indexOf 返回的是子串的下标. 如果 word 在 stringBuilder 中不存在, 则返回下标为 -1
        return stringBuilder.indexOf(word) != -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值