1. 概述

本文将系统性地介绍 Java 中的 File 类,它是 java.io 包的重要组成部分。✅ File 类的核心作用是让我们能够操作文件系统中的文件和目录,比如创建、删除、重命名、获取元数据等。

⚠️ 但必须强调一点:**File 类本身不能读写文件内容**。它只负责文件/目录的“元操作”,真正的读写需要配合 InputStream / OutputStream 等 IO 流来完成。

2. 创建 File 对象

File 类提供了 4 个公共构造函数,开发者可以根据不同场景选择使用:

  • File(String pathname)
    直接通过路径字符串创建 File 实例。

  • File(String parent, String child)
    通过父路径和子路径拼接创建,避免手动拼接路径分隔符。

  • File(File parent, String child)
    父路径用另一个 File 对象表示,适合链式操作。

  • File(URI uri)
    通过 URI 创建,适用于更复杂的资源定位场景。

✅ 推荐使用 File.separator 而不是硬编码 /\,保证跨平台兼容性。

3. File 类常用操作

3.1 创建与删除文件/目录

File 提供了简单粗暴的创建和删除方法:

  • ✅ 创建目录:mkdir()mkdirs()(递归创建)
  • ✅ 创建文件:createNewFile()
  • ✅ 删除:delete()

所有方法返回 boolean,成功为 true,失败为 false(比如文件不存在或权限不足)。

@Test
public void givenDir_whenMkdir_thenDirIsDeleted() {
    File directory = new File("dir");
    assertTrue(directory.mkdir());
    assertTrue(directory.delete());
}

@Test
public void givenFile_whenCreateNewFile_thenFileIsDeleted() {
    File file = new File("file.txt");
    try {
        assertTrue(file.createNewFile());
    } catch (IOException e) {
        fail("Could not create file.txt");
    }
    assertTrue(file.delete());
}

常用判断方法

  • exists():文件或目录是否存在
  • isDirectory():是否是目录
  • isFile():是否是文件

这些方法在操作前做预检非常有用,避免踩坑 ❌。

3.2 获取文件元数据

File 类提供了一些方法来获取路径和结构信息:

  • getName():获取文件名(不含路径)
  • getParentFile():返回父目录的 File 对象
  • getPath():返回构造时传入的路径字符串

示例代码:

@Test
public void givenFile_whenCreateNewFile_thenMetadataIsCorrect() {

    String sep = File.separator;

    File parentDir = makeDir("filesDir");

    File child = new File(parentDir, "file.txt");
    try {
        child.createNewFile();
    } catch (IOException e) {
        fail("Could not create file.txt");
    }

    assertEquals("file.txt", child.getName());
    assertEquals(parentDir.getName(), child.getParentFile().getName());
    assertEquals(parentDir.getPath() + sep + "file.txt", child.getPath());

    removeDir(parentDir);
}

⚠️ 注意 getPath() 返回的是构造路径,不一定是绝对路径。如需绝对路径,使用 getAbsolutePath()

3.3 设置文件权限

File 类支持简单的权限控制,适用于一些基础场景:

  • setWritable(boolean):设置是否可写
  • setReadable(boolean):设置是否可读

一旦设置为不可写/读,再进行对应操作会抛出 IOException

示例:禁止写入

@Test
public void givenReadOnlyFile_whenCreateNewFile_thenCantModFile() {
    File parentDir = makeDir("readDir");

    File child = new File(parentDir, "file.txt");
    try {
        child.createNewFile();
    } catch (IOException e) {
        fail("Could not create file.txt");
    }
    child.setWritable(false);
    boolean writable = true;
    try (FileOutputStream fos = new FileOutputStream(child)) {
        fos.write("Hello World".getBytes());
        fos.flush();
    } catch (IOException e) {
        writable = false;
    } finally {
        removeDir(parentDir);
    }
    assertFalse(writable);
}

示例:禁止读取

@Test
public void givenWriteOnlyFile_whenCreateNewFile_thenCantReadFile() {
    File parentDir = makeDir("writeDir");

    File child = new File(parentDir, "file.txt");
    try {
        child.createNewFile();
    } catch (IOException e) {
        fail("Could not create file.txt");
    }
    child.setReadable(false);
    boolean readable = true;
    try (FileInputStream fis = new FileInputStream(child)) {
        fis.read();
    } catch (IOException e) {
        readable = false;
    } finally {
        removeDir(parentDir);
    }
    assertFalse(readable);
}

⚠️ 这些权限控制在某些操作系统(如 Windows)上可能不生效,建议在关键场景使用更严格的权限管理机制。

3.4 列出目录中的文件

File 提供了两个常用方法来列出目录内容:

  • list():返回文件名字符串数组
  • list(FilenameFilter):支持过滤,只返回符合条件的文件名

示例:过滤 .csv 文件

@Test
public void givenFilesInDir_whenCreateNewFile_thenCanListFiles() {
    File parentDir = makeDir("filtersDir");

    String[] files = {"file1.csv", "file2.txt"};
    for (String file : files) {
        try {
            new File(parentDir, file).createNewFile();
        } catch (IOException e) {
            fail("Could not create " + file);
        }
    }

    // 正常列出
    assertEquals(2, parentDir.list().length);

    // 过滤列出
    FilenameFilter csvFilter = (dir, ext) -> ext.endsWith(".csv");
    assertEquals(1, parentDir.list(csvFilter).length);

    removeDir(parentDir);
}

FilenameFilter 是函数式接口,可以直接用 Lambda 表达式实现,简洁明了。

3.5 重命名文件或目录

使用 renameTo(File dest) 方法可以重命名或移动文件/目录。

@Test
public void givenDir_whenMkdir_thenCanRenameDir() {

    File source = makeDir("source");
    File destination = makeDir("destination");
    boolean renamed = source.renameTo(destination);

    if (renamed) {
        assertFalse(source.isDirectory());
        assertTrue(destination.isDirectory());

        removeDir(destination);
    }
}

⚠️ 注意:

  • renameTo 返回 boolean,失败可能因为目标已存在、权限不足或跨文件系统(某些平台不支持跨分区重命名)。
  • 如果目标文件已存在,行为是平台相关的,通常会失败

3.6 获取磁盘空间信息

File 类还能获取磁盘使用情况,适用于监控或容量预判:

  • getTotalSpace():总空间
  • getFreeSpace():剩余空间
  • getUsableSpace():用户可用空间(考虑配额)

示例:验证写入后剩余空间减少

@Test
public void givenDataWritten_whenWrite_thenFreeSpaceReduces() {

    String home = System.getProperty("user.home");
    String sep = File.separator;
    File testDir = makeDir(home + sep + "test");
    File sample = new File(testDir, "sample.txt");

    long freeSpaceBefore = testDir.getFreeSpace();
    try {
        writeSampleDataToFile(sample);
    } catch (IOException e) {
        fail("Could not write to sample.txt");
    }

    long freeSpaceAfter = testDir.getFreeSpace();
    assertTrue(freeSpaceAfter < freeSpaceBefore);

    removeDir(testDir);
}

✅ 这些方法对根目录或挂载点调用最有效,比如 new File("/")new File("C:\\")

4. 总结

File 类虽然简单,但在传统 IO 操作中仍是不可或缺的基础工具。它提供了对文件系统的基本操作能力,包括:

  • ✅ 文件/目录的创建、删除、重命名
  • ✅ 元数据获取与权限设置
  • ✅ 目录遍历与磁盘空间查询

⚠️ 但也要注意它的局限性:

  • 无法读写文件内容
  • 某些方法行为依赖操作系统
  • 异常处理必须严谨(尤其是 IOException

📌 补充建议:在 Java 7+ 环境中,推荐优先使用 java.nio.file.PathFiles 工具类,它们提供了更强大、更安全的文件操作 API。

所有示例代码已托管至 GitHub:https://github.com/baeldung/core-java-modules/tree/master/core-java-io-apis


原始标题:The Java File Class | Baeldung