51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Java 中的 getResourceAsStream() 和 FileInputStream

1、概览 {#1概览}

本文将带你了解 Java 中读取文件的不同方法之间的差异。主要介绍 getResourceAsStream() 方法和 FileInputStream 类,以及它们的用例。

先说结论,Files.newInputStream() 方法,由于其在内存和性能方面的好处,推荐用于替代 FileInputStream

2、基础知识 {#2基础知识}

首先来了解一下 getResourceAsStream()FileInputStream 之间的区别以及它们的常见用例。

2.1、使用 getResourceAsStream() 读取文件 {#21使用-getresourceasstream-读取文件}

getResourceAsStream() 方法从 classpath 读取文件。传递给 getResourceAsStream() 方法的文件路径应相对于 classpath 。该方法返回一个可用于读取文件的 InputStream

这种方法通常用于读取配置文件、properties 文件和其他与应用打包在一起的资源。

2.2、使用 FileInputStream 读取文件 {#22使用-fileinputstream-读取文件}

FileInputStream 类用于从文件系统中读取文件。当需要读取未与应用打包在一起的文件时(本地磁盘),该类非常有用。

传递给 FileInputStream 构造函数的文件路径应该是绝对路径或与当前工作目录相对的路径。

FileInputStream 对象由于使用了 finalizersfinalize() 方法),可能存在内存和性能问题。FileInputStream 的更好替代方案是 Files.newInputStream() 方法,其工作方式相同。

本文示例中使用 Files.newInputStream() 方法从文件系统中读取文件。

这些方法通常用于读取文件系统中的外部文件,如日志文件、用户数据文件和 Secret 文件。

3、代码示例 {#3代码示例}

让我们通过一个示例来演示 getResourceAsStream()Files.newInputStream() 的用法。

创建一个简单的工具类,使用这两种方法读取文件。然后,通过从 classpath 和文件系统中读取示例文件来测试这两种方法。

3.1、使用 getResourceAsStream() {#31使用-getresourceasstream}

首先,来看看 getResourceAsStream() 方法的用法。

创建一个名为 FileIOUtil 的类,并添加一个从指定资源中读取文件的方法:

static String readFileFromResource(String filePath) {
    try (InputStream inputStream = FileIOUtil.class.getResourceAsStream(filePath)) {
        String result = null;
        if (inputStream != null) {
            result = new BufferedReader(new InputStreamReader(inputStream))
              .lines()
              .collect(Collectors.joining("\n"));
        }
        return result;
    } catch (IOException e) {
        LOG.error("Error reading file:", e);
        return null;
    }
}

在此方法中,我们通过将文件路径作为参数传递给 getResourceAsStream() 方法来获取 InputStream。该文件路径应相对于 classpath。然后,使用 BufferedReader 读取文件内容。该方法逐行读取内容,并使用 Collectors.joining() 方法将它们拼接起来。最后,以 String 形式返回文件内容。

如果出现异常,例如找不到文件,则会被 catch 并返回 null

3.2、使用 Files.newInputStream() {#32使用-filesnewinputstream}

接下来,使用 Files.newInputStream() 定义一个类似的方法:

static String readFileFromFileSystem(String filePath) {
    try (InputStream inputStream = Files.newInputStream(Paths.get(filePath))) {
        return new BufferedReader(new InputStreamReader(inputStream))
          .lines()
          .collect(Collectors.joining("\n"));
    } catch (IOException e) {
        LOG.error("Error reading file:", e);
        return null;
    }
}

在此方法中,我们使用 Files.newInputStream() 方法从文件系统中读取文件。文件路径应为绝对路径或项目目录的相对路径。与前一个方法类似,读取并返回文件内容。

4、测试 {#4测试}

现在,通过读取一个示例来测试这两种方法。

注意观察,在不同情况下文件路径是如何传递给方法的。

4.1、从 Classpath 读取文件 {#41从-classpath-读取文件}

首先,比较一下这些方法如何从 classpath 读取文件。

src/main/resources 目录下创建一个名为 test.txt 的文件,并在其中添加一些内容:

Hello!
Welcome to the world of Java NIO.

使用两种方法读取该文件并验证其内容:

@Test
void givenFileUnderResources_whenReadFileFromResource_thenSuccess() {
    String result = FileIOUtil.readFileFromResource("/test.txt");
    assertNotNull(result);
    assertEquals(result, "Hello!\n" + "Welcome to the world of Java NIO.");
}

@Test
void givenFileUnderResources_whenReadFileFromFileSystem_thenSuccess() {
    String result = FileIOUtil.readFileFromFileSystem("src/test/resources/test.txt");
    assertNotNull(result);
    assertEquals(result, "Hello!\n" + "Welcome to the world of Java NIO.");
}

我们可以看到,这两种方法都读取了文件 test.txt,并返回其内容。然后,比较文件内容,确保它们与预期值一致。这两种方法的区别在于作为参数传递的文件路径

readFileFromResource() 方法需要一个相对于 classpath 的路径。由于文件直接位于 src/main/resources 目录下,因此将 /test.txt 作为文件路径。

而,readFileFromFileSystem() 方法需要一个绝对路径或与当前工作目录相对的路径。我们传递 src/main/resources/test.txt 作为文件路径。或者,也可以传递文件的绝对路径,如 /path/to/project/src/main/resources/test.txt

4.2、从文件系统读取文件 {#42从文件系统读取文件}

在项目目录外创建一个名为 external.txt 的文件,并尝试使用这两种方法读取该文件。

创建测试方法,使用这两种方法读取文件:

@Test
void givenFileOutsideResources_whenReadFileFromFileSystem_thenSuccess() {
    String result = FileIOUtil.readFileFromFileSystem("../external.txt");
    assertNotNull(result);
    assertEquals(result, "Hello!\n" + "Welcome to the world of Java NIO.");
}

@Test
void givenFileOutsideResources_whenReadFileFromResource_thenNull() {
    String result = FileIOUtil.readFileFromResource("../external.txt");
    assertNull(result);
}

如上,我们传递的是 external.txt 文件的相对路径。readFileFromFileSystem() 方法直接从文件系统读取文件并返回其内容。

如果尝试使用 readFileFromResource() 方法读取文件,它将返回空值,因为文件不在 classpath 中。

5、总结 {#5总结}

本文介绍了使用 getResourceAsStream() 从 classpath 读取文件与使用 Files.newInputStream() 从文件系统读取文件之间的区别。


Ref:https://www.baeldung.com/java-getresourceasstream-vs-fileinputstream

赞(0)
未经允许不得转载:工具盒子 » Java 中的 getResourceAsStream() 和 FileInputStream