Skip to content

Java IO - 01 前置知识之File类

本文主要介绍java.io.File类相关知识。File代表了操作系统上的文件或文件夹(目录)。

1. 创建File对象

File类提供了以下四个构造方法创建对象:

  • public File(String pathname):通过路径创建对象;
  • public File(String parent, String child):通过父路径和子路径创建对象;
  • public File(File parent, String child):通过File父对象和子路径创建对象;
  • public File(URI uri):通过URI创建对象;

1.1 相对路径和绝对路径

  • 绝对路径是从文件系统的根目录开始的完整路径。它提供了从根目录到目标文件或目录的完整路径信息。

    在在macOS或Linux操作系统中,绝对路径以/开始,例如/home/a.txt;在Windows系统中,绝对路径以盘符开始,例如C:/demo.txt

  • 相对路径是从当前工作目录开始的路径。它提供了从当前工作目录到目标文件或目录的路径信息。

在路径的表示中,有两个特殊符号表示特别的含义:

  • .表示当前目录;
  • ..表示父目录;

两个符号在相对路径和绝对路径中都可以使用。

以下是使用相对路径和绝对路径来创建File对象的示例(以macOS系统为例):

java
// 示例一:以绝对路径表示文件夹
File f1 = new File("/Users/smz/projects/demo/java_demo"); 

// 示例二:以绝对路径表示文件
File f2 = new File("/Users/smz/projects/demo/java_demo/a.txt"); 

// 示例三:在绝对路径中使用特殊符号
File f3 = new File("/Users/smz/projects/demo/java_demo/.."); 
// 实际表示/Users/smz/projects/demo文件夹

// 示例四:以相对路径表示当前项目工程路径
File f4 = new File("");
File f5 = new File(".");

我们也可以使用File表示不存在的文件或目录,例如:

java
File f = new File("/xxx/non_exist.txt");

所以File类中提供了exists()方法表示该文件或目录是否存在。

Java
System.out.println(f.exists());

当我们想输出文件路径时,File类提供了相关方法:

  • getCanonicalPath() 方法用于获取文件或目录的规范路径(Canonical Path)。规范路径是指文件系统中唯一标识文件或目录的路径,它消除了路径中的冗余部分,如 ...,并解析为绝对路径
  • getAbsolutePath()方法获取文件或目录的绝对路径,它不会消除路径中的冗余部分(如...)。

1.2 URI、URL和URN

TIP

URI是抽象的资源标识,而URL和URN是具体的资源标识实现。

1.2.1 URI (Uniform Resource Identifier)

URI 是统一资源标识符(Uniform Resource Identifier)的缩写,它是一个用于标识某一互联网资源名称的字符串。URI 可以用来标识资源的位置或名称,或者两者兼有。

URI 的一般格式为:

scheme:[//authority]path[?query][#fragment]
  • scheme:协议类型,如 httphttpsftpfile 等。
  • authority:通常包括主机名和端口号,如 www.example.com:8080
  • path:资源路径,如 /index.html
  • query:查询参数,如 ?key=value
  • fragment:锚点,如 #section1

1.2.2 URL (Uniform Resource Locator)

URL 是统一资源定位符(Uniform Resource Locator)的缩写,它是 URI 的一个子集,用于标识资源的位置。URL 通常包含协议、主机名、端口号、路径、查询参数和锚点。

例如:

  • http://www.example.com/index.html?name=Kimi#section1
  • ftp://ftp.example.com/downloads/file.zip

1.2.3 URN (Uniform Resource Name)

URN 是统一资源名称(Uniform Resource Name)的缩写,它是 URI 的另一个子集,用于标识资源的名称,而不是位置。URN 通常用于标识资源的唯一名称,而不依赖于资源的具体位置。

URN 的格式通常以 urn: 开头,后跟具体的命名空间和资源名称。

urn:<namespace>:<specific-name>

示例

  • urn:isbn:0451450523(标识一本书的 ISBN 号)

1.3 资源目录

在maven项目中,资源文件默认位置如下:

  • 主代码资源文件src/main/resources
  • 测试代码资源文件src/test/resources

在项目构建时(如执行 mvn package),src/main/resources 下的文件会被复制到 target/classes 目录中,并**合并到类路径(classpath)**下。同理,src/test/resources 下的文件会复制到 target/test-classes 中,仅在测试时可用。

由于资源文件会被打包到 JAR/WAR 的类路径根目录下,因此代码中应使用 相对类路径 的路径表示方式。

  • getResource("/") 中的 / 表示类路径的根目录(即 target/classes)。
  • ClassLoader.getResource("") 不需要前导 /,直接使用相对路径。
java
URL resource = FileTest.class.getClassLoader().getResource("");
System.out.println(resource);

URL resource1 = FileTest.class.getResource("");
System.out.println(resource1);

结果如下:

txt
file:/Users/smz/projects/demo/java_demo/target/classes/
file:/Users/smz/projects/demo/java_demo/target/classes/com/lee/bio/

如果在maven项目中需要访问资源目录中的资源,需要使用相对类路径的表示方法,不应该使用相对路径或绝对路径。

java
URL resource = FileTest.class.getClassLoader().getResource("data.txt");
File file = new File(resource.getPath());

2. 路径分隔符

在File类中,提供了两个静态属性:separatorpathSeparator

File.separator:表示单个路径中的目录分隔符,用于分隔文件路径中的不同层级目录。在Windows平台下是\,在Linux或macOS下是/。例如:

java
String path = "data" + File.separator + "config" + File.separator + "app.properties";
// Windows: data\config\app.properties
// Linux: data/config/app.properties

File.pathSeparator:表示多个路径之间的分隔符,用于分隔环境变量(如 PATHCLASSPATH)中的不同路径。在Windows下是;,在Linux或macOS下是:。例如:

java
String classpath = "/path/to/jar1" + File.pathSeparator + "/path/to/jar2";
// Windows: /path/to/jar1;/path/to/jar2
// Linux: /path/to/jar1:/path/to/jar2

3. 常用方法

本小节列举File类中常用的方法:

  • public long length():以字节数返回文件或文件夹的大小,注意,如果是文件夹,只会返回文件夹本身的大小而不包括文件夹内容的大小;

  • public long lastModified():返回文件或文件夹最近修改时间,返回的是自1970-01-01 00:00:00经过的毫秒数,我们可以用下面的方式格式化:

    java
    // 方式一
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    simpleDateFormat.format(file.lastModified());
    
    // 方式二
    LocalDateTime.ofInstant(Instant.ofEpochMilli(file.lastModified()), ZoneId.systemDefault())
  • public String getParent():返回文件或文件夹的父目录;

  • public boolean isFile():判断调用对象是否为文件;

  • public boolean isDirectory():判断调用对象是否为文件夹;

  • public boolean exists():判断调用对象是否存在;

  • public String getAbsolutePath():返回绝对路径(不规范的);

  • public String getCanonicalPath():返回规范的绝对路径;

  • public String getPath():返回创建File对象时传入的路径,例如:

    java
    File file = new File("/Users/smz/notes");
    File file1 = new File("");
    
    System.out.println(file.getPath());  // 结果:/Users/smz/notes
    System.out.println(file1.getPath());  // 结果(空格):
  • public String getName():基于创建File对象时传入的路径,返回文件或文件夹名称,例如:

    java
    File file = new File("/Users/smz/notes");
    File file1 = new File("");
    
    System.out.println(file.getName());  // 结果:notes
    System.out.println(file1.getName());  // 结果(空格):
  • public boolean createNewFile():创建新文件,需父目录存在;

  • public boolean mkdir():创建单层目录(父目录必须存在);

  • public boolean mkdirs():创建多层目录(自动创建不存在的父目录);

  • public boolean renameTo(File dest):重命名文件或目录;

  • public boolean delete():删除文件或空目录(非空目录返回 false);

  • public String[] list():返回目录下的文件和子目录名称数组(非目录返回 null);

  • public File[] listFiles():返回目录下的 File 对象数组(非目录返回 null);

4. 遍历文件夹案例

本小节使用listFiles()方法来遍历文件夹,在使用listFiles()方法时,需要注意以下内容:

  • 当调用对象是文件,或者路径不存在时,返回null;
  • 当调用对象是空文件夹时,返回一个长度为0的数组;
  • 当调用对象是一个有内容的文件夹时,将里面所有的一级文件(包含隐藏文件)和文件夹返回;
  • 当调用对象是一个文件夹,但是没有权限访问该文件夹时,返回null;
java
private void listFile(File dir, int level) throws IOException {
    if(dir == null || !dir.exists()){
        return;
    }

    System.out.print(blankString(level));
    System.out.println(dir.getCanonicalPath());

    if(dir.isFile()){
        return;
    }

    for (File file : dir.listFiles()) {
        listFile(file, level+1);
    }

}

private String blankString(int level){
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < level; i++){
        sb.append(' ');
    }
    return sb.toString();
}