• Java – 从资源文件夹中读取文件


    在Java中,我们可以使用getResourceAsStreamgetResource从​​​​​​​resources文件夹或类路径的根读取一个或多个文件。

    getResourceAsStream方法返回一个InputStream .​​​​​​​

    1. // the stream holding the file content
    2. InputStream is = getClass().getClassLoader().getResourceAsStream("file.txt");
    3. // for static access, uses the class name directly
    4. InputStream is = JavaClassName.class.getClassLoader().getResourceAsStream("file.txt");

    getResource方法返回 一个​​​​​​​URL,通常将其转换为File ;在 JAR 文件中不起作用

    1. // get the file url, not working in JAR file.
    2. URL resource = getClass().getClassLoader().getResource("file.txt");
    3. if (resource == null) {
    4. throw new IllegalArgumentException("file not found!");
    5. } else {
    6. // failed if files have whitespaces or special characters
    7. //return new File(resource.getFile());
    8. return new File(resource.toURI());
    9. }
    10. // for static access
    11. // URL resource = JavaClassName.class.getClassLoader().getResource("fileName");

    1. 资源文件夹中的文件

    1.1 查看src/main/resources中的文件,稍后我们将访问这些文件并打印出文件内容。

    src/main/resources/database.properties

    1. datasource.url=jdbc:mysql://localhost/favtuts?useSSL=false
    2. datasource.username=root
    3. datasource.password=password
    4. datasource.driver-class-name=com.mysql.jdbc.Driver

    src/main/resources/json/file1.json

    1. {
    2. "name": "favtuts",
    3. "age": 38
    4. }

    src/main/resources/json/file2.json

    1. {
    2. "name": "jack",
    3. "age": 40
    4. }

    src/main/resources/json/sub/subfile1.json

    1. {
    2. "name": "sub",
    3. "age": 99
    4. }

    1.2 默认情况下,构建工具(如 Maven、Gradle 或常见的 Java 实践)会将所有文件从src/main/resources复制到target/classesbuild/classes​​​​​​​的根目录。因此,当我们尝试从src/main/resources读取文件时,我们从项目类路径的根读取该文件。​​​​​​​​​​​​​​

    1.3 下面是一个 JAR 文件结构。通常,resources文件夹中的文件将复制到类路径的根目录。

    1. $ jar -tf target/example.jar
    2. META-INF/MANIFEST.MF
    3. META-INF/
    4. json/
    5. json/sub/
    6. json/file2.json
    7. json/sub/subfile1.json
    8. json/file1.json
    9. database.properties
    10. com/
    11. com/favtuts/
    12. com/favtuts/io/
    13. com/favtuts/io/utils/
    14. //...

    2. 从资源文件夹中获取文件。

    2.1 下面的示例演示如何使用getResourceAsStreamgetResource方法从resources文件夹中读取​​​​​​​​​​​​​​json/file1.json文件并打印出文件内容。

    注意

    • getResource方法在 JAR 文件中不起作用。
    • getResourceAsStream方法在任何地方都有效。

    FileResourcesUtils.java

    1. package com.favtuts.io.utils;
    2. import java.io.BufferedReader;
    3. import java.io.File;
    4. import java.io.IOException;
    5. import java.io.InputStream;
    6. import java.io.InputStreamReader;
    7. import java.net.URISyntaxException;
    8. import java.net.URL;
    9. import java.nio.charset.StandardCharsets;
    10. import java.nio.file.Files;
    11. import java.util.List;
    12. public class FileResourcesUtils {
    13. public static void main(String[] args) throws Exception {
    14. FileResourcesUtils app = new FileResourcesUtils();
    15. //String fileName = "database.properties";
    16. String fileName = "json/file1.json";
    17. System.out.println("getResourceAsStream : " + fileName);
    18. InputStream is = app.getFileFromResourceAsStream(fileName);
    19. printInputStream(is);
    20. System.out.println("\ngetResource : " + fileName);
    21. File file = app.getFileFromResource(fileName);
    22. printFile(file);
    23. }
    24. // get a file from the resources folder
    25. // works everywhere, IDEA, unit test and JAR file.
    26. private InputStream getFileFromResourceAsStream(String fileName) {
    27. // The class loader that loaded the class
    28. ClassLoader classLoader = getClass().getClassLoader();
    29. InputStream inputStream = classLoader.getResourceAsStream(fileName);
    30. // the stream holding the file content
    31. if (inputStream == null) {
    32. throw new IllegalArgumentException("file not found! " + fileName);
    33. } else {
    34. return inputStream;
    35. }
    36. }
    37. /*
    38. The resource URL is not working in the JAR
    39. If we try to access a file that is inside a JAR,
    40. It throws NoSuchFileException (linux), InvalidPathException (Windows)
    41. Resource URL Sample: file:java-io.jar!/json/file1.json
    42. */
    43. private File getFileFromResource(String fileName) throws URISyntaxException{
    44. ClassLoader classLoader = getClass().getClassLoader();
    45. URL resource = classLoader.getResource(fileName);
    46. if (resource == null) {
    47. throw new IllegalArgumentException("file not found! " + fileName);
    48. } else {
    49. // failed if files have whitespaces or special characters
    50. //return new File(resource.getFile());
    51. return new File(resource.toURI());
    52. }
    53. }
    54. // print input stream
    55. private static void printInputStream(InputStream is) {
    56. try (InputStreamReader streamReader =
    57. new InputStreamReader(is, StandardCharsets.UTF_8);
    58. BufferedReader reader = new BufferedReader(streamReader)) {
    59. String line;
    60. while ((line = reader.readLine()) != null) {
    61. System.out.println(line);
    62. }
    63. } catch (IOException e) {
    64. e.printStackTrace();
    65. }
    66. }
    67. // print a file
    68. private static void printFile(File file) {
    69. List lines;
    70. try {
    71. lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
    72. lines.forEach(System.out::println);
    73. } catch (IOException e) {
    74. e.printStackTrace();
    75. }
    76. }
    77. }

    输出

    1. getResourceAsStream : json/file1.json
    2. {
    3. "name": "favtuts",
    4. "age": 38
    5. }
    6. getResource : json/file1.json
    7. {
    8. "name": "favtuts",
    9. "age": 38
    10. }

    2.2 现在,我们将项目打包到一个JAR文件中并运行它;这一次,getResource将失败并返回NoSuchFileExceptionInvalidPathException。我们无法通过资源 URL 读取 JAR 文件中的文件。​​​​​​​​​​​​​​

    在 Linux (Ubuntu) 上运行 JAR 文件,它会引发NoSuchFileException

    1. $ mvn clean package
    2. $ java -jar target/java-io.jar
    3. $ jar tf target/java-io.jar | more
    4. $ java -cp target/java-io.jar com.favtuts.io.utils.FileResourcesUtils
    5. getResourceAsStream : json/file1.json
    6. {
    7. "name": "favtuts",
    8. "age": 38
    9. }
    10. # for new File(resource.getFile());
    11. getResource : json/file1.json
    12. java.nio.file.NoSuchFileException: file:/home/favtuts/projects/core-java/java-io/target/java-io.jar!/json/file1.json
    13. at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
    14. at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
    15. at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
    16. at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:219)
    17. at java.base/java.nio.file.Files.newByteChannel(Files.java:370)
    18. at java.base/java.nio.file.Files.newByteChannel(Files.java:421)
    19. at java.base/java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:420)
    20. at java.base/java.nio.file.Files.newInputStream(Files.java:155)
    21. at java.base/java.nio.file.Files.newBufferedReader(Files.java:2838)
    22. at java.base/java.nio.file.Files.readAllLines(Files.java:3329)
    23. at com.favtuts.io.utils.FileResourcesUtils.printFile(FileResourcesUtils.java:135)
    24. at com.favtuts.io.utils.FileResourcesUtils.main(FileResourcesUtils.java:24)
    25. # for new File(resource.toURI());
    26. getResource : json/file1.json
    27. Exception in thread "main" java.lang.IllegalArgumentException: URI is not hierarchical
    28. at java.base/java.io.File.(File.java:420)
    29. at com.favtuts.io.utils.FileResourcesUtils.getFileFromResource(FileResourcesUtils.java:112)
    30. at com.favtuts.io.utils.FileResourcesUtils.main(FileResourcesUtils.java:29)

    您可能会收到以下消息

    no main manifest attribute, in "java-io.jar"

    要解决此问题,请阅读堆栈溢出:无法执行 jar 文件:“无主清单属性”中的指南

    对于 Maven,我们应该使用在 pom 中定义的 maven-jar 插件.xml:

    1. <plugin>
    2. <groupId>org.apache.maven.pluginsgroupId>
    3. <artifactId>maven-jar-pluginartifactId>
    4. <version>3.2.0version>
    5. <configuration>
    6. <excludes>
    7. <exclude>**/log4j.propertiesexclude>
    8. excludes>
    9. <archive>
    10. <manifest>
    11. <addClasspath>trueaddClasspath>
    12. <mainClass>com.favtuts.io.utils.FileResourcesUtilsmainClass>
    13. <classpathPrefix>dependency-jars/classpathPrefix>
    14. manifest>
    15. archive>
    16. configuration>
    17. plugin>

    附言:此示例使用 Maven 插件创建 JAR 文件。

    要检查 jar 文件中的主类,请执行以下操作:

    $ jar tf target/java-io.jar | more

    3. 从资源文件夹获取文件 – 单元测试

    3.1 我们将测试资源放在单元测试的src/test/resources文件夹中。通常,测试资源中的文件将复制到target/test-classes文件夹。

    src/test/resources/json/file1.json

    1. {
    2. "name": "unit test",
    3. "age": 38
    4. }

    src/test/resources/database.properties.properties

    1. datasource.url=jdbc:mysql://localhost/test?useSSL=false
    2. datasource.username=test
    3. datasource.password=password
    4. datasource.driver-class-name=com.mysql.jdbc.Driver

    3.2 它的工作方式与我们从src/main/resources中读取文件的方式相同。我们使用相同的getResourceAsStreamgetResource方法从 ​​​​​​​​​​​​​​​​​​​​​src/test/resources读取文件.

    FileResourcesTest.java

    1. package com.favtuts.io;
    2. import java.io.BufferedReader;
    3. import java.io.File;
    4. import java.io.IOException;
    5. import java.io.InputStream;
    6. import java.io.InputStreamReader;
    7. import java.net.URISyntaxException;
    8. import java.net.URL;
    9. import java.nio.charset.StandardCharsets;
    10. import java.nio.file.Files;
    11. import java.util.List;
    12. import org.junit.jupiter.api.DisplayName;
    13. import org.junit.jupiter.api.Test;
    14. // Unit test class
    15. public class FileResourcesTest {
    16. @DisplayName("Test loading a JSON file")
    17. @Test
    18. void loadJSONTest() {
    19. String fileName = "json/file1.json";
    20. ClassLoader classLoader = getClass().getClassLoader();
    21. try (InputStream inputStream = classLoader.getResourceAsStream(fileName);
    22. InputStreamReader streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
    23. BufferedReader reader = new BufferedReader(streamReader)
    24. ) {
    25. String line;
    26. while((line = reader.readLine()) != null) {
    27. System.out.println(line);
    28. }
    29. } catch (IOException e) {
    30. e.printStackTrace();
    31. }
    32. }
    33. @DisplayName("Test loading a properties file")
    34. @Test
    35. void loadPropTest() throws IOException, URISyntaxException {
    36. String fileName = "database.properties";
    37. ClassLoader classLoader = getClass().getClassLoader();
    38. URL resource = classLoader.getResource(fileName);
    39. if (resource == null) {
    40. throw new IllegalArgumentException("file not found! " + fileName);
    41. }
    42. //File file = new File(resource.getFile());
    43. File file = new File(resource.toURI());
    44. List lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
    45. lines.forEach(System.out::println);
    46. }
    47. }

    输出

    1. {
    2. "name": "unit test",
    3. "age": 38
    4. }
    5. datasource.url=jdbc:mysql://localhost/test?useSSL=false
    6. datasource.username=test
    7. datasource.password=password
    8. datasource.driver-class-name=com.mysql.jdbc.Driver

    4. 从资源文件夹中获取所有文件。(非 JAR 环境)

    如果我们不知道确切的文件名,并且想要读取所有文件,包括资源文件夹中的子文件夹文件,我们可以使用NIO Files.walk轻松访问和读取文件。

    4.1 以下示例使用​​​​​​​Files.walk从​​​​​​​src/main/resources/json文件夹中读取所有文件:

    FileResourcesUtils.java

    p
    1. package com.favtuts.io.utils;
    2. import java.io.*;
    3. import java.net.URISyntaxException;
    4. import java.net.URL;
    5. import java.nio.charset.StandardCharsets;
    6. import java.nio.file.Files;
    7. import java.nio.file.Paths;
    8. import java.util.List;
    9. import java.util.stream.Collectors;
    10. public class FileResourcesUtils {
    11. public static void main(String[] args) throws IOException {
    12. FileResourcesUtils app = new FileResourcesUtils();
    13. // read all files from a resources folder
    14. try {
    15. // files from src/main/resources/json
    16. List result = app.getAllFilesFromResource("json");
    17. for (File file : result) {
    18. System.out.println("file : " + file);
    19. printFile(file);
    20. }
    21. } catch (URISyntaxException | IOException e) {
    22. e.printStackTrace();
    23. }
    24. }
    25. private List getAllFilesFromResource(String folder)
    26. throws URISyntaxException, IOException {
    27. ClassLoader classLoader = getClass().getClassLoader();
    28. URL resource = classLoader.getResource(folder);
    29. // dun walk the root path, we will walk all the classes
    30. List collect = Files.walk(Paths.get(resource.toURI()))
    31. .filter(Files::isRegularFile)
    32. .map(x -> x.toFile())
    33. .collect(Collectors.toList());
    34. return collect;
    35. }
    36. // print a file
    37. private static void printFile(File file) {
    38. List lines;
    39. try {
    40. lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
    41. lines.forEach(System.out::println);
    42. } catch (IOException e) {
    43. e.printStackTrace();
    44. }
    45. }
    46. }

    输出

    1. file : /home/favtuts/projects/core-java/java-io/target/classes/json/file1.json
    2. {
    3. "name": "favtuts",
    4. "age": 38
    5. }
    6. file : /home/favtuts/projects/core-java/java-io/target/classes/json/file2.json
    7. {
    8. "name": "jack",
    9. "age": 40
    10. }
    11. file : /home/favtuts/projects/core-java/java-io/target/classes/json/sub/subfile1.json
    12. {
    13. "name": "sub",
    14. "age": 99
    15. }

    4.2 但是,示例 4.1 中的标准Files.walk无法直接访问 JAR 文件中的文件,请尝试在 JAR 环境中运行示例 4.1,然后它会引发FileSystemNotFoundException。​​​​​​​

    1. $ mvn clean package
    2. $ java -jar target/java-io.jar
    3. Exception in thread "main" java.nio.file.FileSystemNotFoundException
    4. at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:169)
    5. at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:155)
    6. at java.base/java.nio.file.Path.of(Path.java:208)
    7. at java.base/java.nio.file.Paths.get(Paths.java:97)
    8. at com.favtuts.io.utils.FileResourcesUtils.getAllFilesFromResource(FileResourcesUtils.java:128)
    9. at com.favtuts.io.utils.FileResourcesUtils.main(FileResourcesUtils.java:35)

    5. 从资源文件夹中获取所有文件。(JAR 版本)

    5.1 此示例演示Files.walk如何通过FileSystemsjar:file:xxx.jar URI读取 JAR 文件内的文件夹 。​​​​​​​​​​​​​​

    这个想法是:

    • 文件使用FileSystems在 JAR 文件中遍历文件夹,并获取所有文件名,请参见​​​​​​​getPathsFromResourceJAR()
    • 循环所有文件名,访问并打印每个文件,如示例 2.1,请参阅getFileFromResourceAsStream()

    FileResourcesUtils.java

    1. package com.favtuts.io.utils;
    2. import java.io.*;
    3. import java.net.URI;
    4. import java.net.URISyntaxException;
    5. import java.nio.charset.StandardCharsets;
    6. import java.nio.file.FileSystem;
    7. import java.nio.file.FileSystems;
    8. import java.nio.file.Files;
    9. import java.nio.file.Path;
    10. import java.util.Collections;
    11. import java.util.List;
    12. import java.util.stream.Collectors;
    13. public class FileResourcesUtils {
    14. public static void main(String[] args) throws IOException {
    15. FileResourcesUtils app = new FileResourcesUtils();
    16. // Sample 3 - read all files from a resources folder (JAR version)
    17. try {
    18. // get paths from src/main/resources/json
    19. List result = app.getPathsFromResourceJAR("json");
    20. for (Path path : result) {
    21. System.out.println("Path : " + path);
    22. String filePathInJAR = path.toString();
    23. // Windows will returns /json/file1.json, cut the first /
    24. // the correct path should be json/file1.json
    25. if (filePathInJAR.startsWith("/")) {
    26. filePathInJAR = filePathInJAR.substring(1, filePathInJAR.length());
    27. }
    28. System.out.println("filePathInJAR : " + filePathInJAR);
    29. // read a file from resource folder
    30. InputStream is = app.getFileFromResourceAsStream(filePathInJAR);
    31. printInputStream(is);
    32. }
    33. } catch (URISyntaxException | IOException e) {
    34. e.printStackTrace();
    35. }
    36. }
    37. // get a file from the resources folder
    38. // works everywhere, IDEA, unit test and JAR file.
    39. private InputStream getFileFromResourceAsStream(String fileName) {
    40. // The class loader that loaded the class
    41. ClassLoader classLoader = getClass().getClassLoader();
    42. InputStream inputStream = classLoader.getResourceAsStream(fileName);
    43. // the stream holding the file content
    44. if (inputStream == null) {
    45. throw new IllegalArgumentException("file not found! " + fileName);
    46. } else {
    47. return inputStream;
    48. }
    49. }
    50. // Get all paths from a folder that inside the JAR file
    51. private List getPathsFromResourceJAR(String folder)
    52. throws URISyntaxException, IOException {
    53. List result;
    54. // get path of the current running JAR
    55. String jarPath = getClass().getProtectionDomain()
    56. .getCodeSource()
    57. .getLocation()
    58. .toURI()
    59. .getPath();
    60. System.out.println("JAR Path :" + jarPath);
    61. // file walks JAR
    62. URI uri = URI.create("jar:file:" + jarPath);
    63. try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
    64. result = Files.walk(fs.getPath(folder))
    65. .filter(Files::isRegularFile)
    66. .collect(Collectors.toList());
    67. }
    68. return result;
    69. }
    70. // print input stream
    71. private static void printInputStream(InputStream is) {
    72. try (InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8);
    73. BufferedReader reader = new BufferedReader(streamReader)) {
    74. String line;
    75. while ((line = reader.readLine()) != null) {
    76. System.out.println(line);
    77. }
    78. } catch (IOException e) {
    79. e.printStackTrace();
    80. }
    81. }
    82. }

    输出

    1. $ java -jar target/java-io.jar
    2. JAR Path :/C:/Users/favtuts/projects/core-java/java-io/target/java-io.jar
    3. Path : /json/file2.json
    4. filePathInJAR : json/file2.json
    5. {
    6. "name": "jack",
    7. "age": 40
    8. }
    9. Path : /json/file1.json
    10. filePathInJAR : json/file1.json
    11. {
    12. "name": "favtuts",
    13. "age": 38
    14. }
    15. Path : /json/sub/subfile1.json
    16. filePathInJAR : json/sub/subfile1.json
    17. {
    18. "name": "sub",
    19. "age": 99
    20. }

    下载源代码

    $ git clone https://github.com/favtuts/java-core-tutorials-examples

    $ cd java-io

  • 相关阅读:
    kubernetes安装并测试
    AI重塑千行百业,华为云发布盘古大模型3.0和昇腾AI云服务
    基于XXL-JOB分布式任务的实现
    基于PHP+MySQL协同办公系统的设计与实现
    分类问题的评价指标
    【QT】设置焦点及光标位置
    Java项目:中药药方管理系统(java+SSM+JSP+bootstrap+Mysql)
    六月集训(28)动态规划
    Python selenium模块的常用方法【更新中】
    ECCV2022 | 人大提出轻量级基于注意力的特征融合机制,在多个公开数据集上有效!代码已开源!
  • 原文地址:https://blog.csdn.net/allway2/article/details/127128371