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

getResourceAsStream方法返回一个InputStream .
- // the stream holding the file content
- InputStream is = getClass().getClassLoader().getResourceAsStream("file.txt");
-
- // for static access, uses the class name directly
- InputStream is = JavaClassName.class.getClassLoader().getResourceAsStream("file.txt");
getResource方法返回 一个URL,通常将其转换为File ;在 JAR 文件中不起作用。
- // get the file url, not working in JAR file.
- URL resource = getClass().getClassLoader().getResource("file.txt");
- if (resource == null) {
- throw new IllegalArgumentException("file not found!");
- } else {
-
- // failed if files have whitespaces or special characters
- //return new File(resource.getFile());
-
- return new File(resource.toURI());
- }
-
- // for static access
- // URL resource = JavaClassName.class.getClassLoader().getResource("fileName");
1.1 查看src/main/resources中的文件,稍后我们将访问这些文件并打印出文件内容。

src/main/resources/database.properties
- datasource.url=jdbc:mysql://localhost/favtuts?useSSL=false
- datasource.username=root
- datasource.password=password
- datasource.driver-class-name=com.mysql.jdbc.Driver
src/main/resources/json/file1.json
- {
- "name": "favtuts",
- "age": 38
- }
src/main/resources/json/file2.json
- {
- "name": "jack",
- "age": 40
- }
src/main/resources/json/sub/subfile1.json
- {
- "name": "sub",
- "age": 99
- }
1.2 默认情况下,构建工具(如 Maven、Gradle 或常见的 Java 实践)会将所有文件从src/main/resources复制到target/classes或build/classes的根目录。因此,当我们尝试从src/main/resources读取文件时,我们从项目类路径的根读取该文件。

1.3 下面是一个 JAR 文件结构。通常,resources文件夹中的文件将复制到类路径的根目录。
- $ jar -tf target/example.jar
- META-INF/MANIFEST.MF
- META-INF/
- json/
- json/sub/
- json/file2.json
- json/sub/subfile1.json
- json/file1.json
- database.properties
- com/
- com/favtuts/
- com/favtuts/io/
- com/favtuts/io/utils/
- //...
2.1 下面的示例演示如何使用getResourceAsStream和getResource方法从resources文件夹中读取json/file1.json文件并打印出文件内容。
注意
getResource方法在 JAR 文件中不起作用。getResourceAsStream方法在任何地方都有效。FileResourcesUtils.java
- package com.favtuts.io.utils;
-
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.net.URISyntaxException;
- import java.net.URL;
- import java.nio.charset.StandardCharsets;
- import java.nio.file.Files;
- import java.util.List;
-
- public class FileResourcesUtils {
-
- public static void main(String[] args) throws Exception {
-
- FileResourcesUtils app = new FileResourcesUtils();
-
- //String fileName = "database.properties";
- String fileName = "json/file1.json";
-
- System.out.println("getResourceAsStream : " + fileName);
- InputStream is = app.getFileFromResourceAsStream(fileName);
- printInputStream(is);
-
- System.out.println("\ngetResource : " + fileName);
- File file = app.getFileFromResource(fileName);
- printFile(file);
-
- }
-
- // get a file from the resources folder
- // works everywhere, IDEA, unit test and JAR file.
- private InputStream getFileFromResourceAsStream(String fileName) {
-
- // The class loader that loaded the class
- ClassLoader classLoader = getClass().getClassLoader();
- InputStream inputStream = classLoader.getResourceAsStream(fileName);
-
- // the stream holding the file content
- if (inputStream == null) {
- throw new IllegalArgumentException("file not found! " + fileName);
- } else {
- return inputStream;
- }
-
- }
-
- /*
- The resource URL is not working in the JAR
- If we try to access a file that is inside a JAR,
- It throws NoSuchFileException (linux), InvalidPathException (Windows)
- Resource URL Sample: file:java-io.jar!/json/file1.json
- */
- private File getFileFromResource(String fileName) throws URISyntaxException{
-
- ClassLoader classLoader = getClass().getClassLoader();
- URL resource = classLoader.getResource(fileName);
- if (resource == null) {
- throw new IllegalArgumentException("file not found! " + fileName);
- } else {
-
- // failed if files have whitespaces or special characters
- //return new File(resource.getFile());
-
- return new File(resource.toURI());
- }
-
- }
-
- // print input stream
- private static void printInputStream(InputStream is) {
-
- try (InputStreamReader streamReader =
- new InputStreamReader(is, StandardCharsets.UTF_8);
- BufferedReader reader = new BufferedReader(streamReader)) {
-
- String line;
- while ((line = reader.readLine()) != null) {
- System.out.println(line);
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- // print a file
- private static void printFile(File file) {
-
- List
lines; - try {
- lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
- lines.forEach(System.out::println);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
- }
输出
- getResourceAsStream : json/file1.json
- {
- "name": "favtuts",
- "age": 38
- }
- getResource : json/file1.json
- {
- "name": "favtuts",
- "age": 38
- }
2.2 现在,我们将项目打包到一个JAR文件中并运行它;这一次,getResource将失败并返回NoSuchFileException或InvalidPathException。我们无法通过资源 URL 读取 JAR 文件中的文件。
在 Linux (Ubuntu) 上运行 JAR 文件,它会引发NoSuchFileException。
- $ mvn clean package
- $ java -jar target/java-io.jar
- $ jar tf target/java-io.jar | more
- $ java -cp target/java-io.jar com.favtuts.io.utils.FileResourcesUtils
- getResourceAsStream : json/file1.json
- {
- "name": "favtuts",
- "age": 38
- }
- # for new File(resource.getFile());
- getResource : json/file1.json
- java.nio.file.NoSuchFileException: file:/home/favtuts/projects/core-java/java-io/target/java-io.jar!/json/file1.json
- at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
- at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
- at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
- at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:219)
- at java.base/java.nio.file.Files.newByteChannel(Files.java:370)
- at java.base/java.nio.file.Files.newByteChannel(Files.java:421)
- at java.base/java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:420)
- at java.base/java.nio.file.Files.newInputStream(Files.java:155)
- at java.base/java.nio.file.Files.newBufferedReader(Files.java:2838)
- at java.base/java.nio.file.Files.readAllLines(Files.java:3329)
- at com.favtuts.io.utils.FileResourcesUtils.printFile(FileResourcesUtils.java:135)
- at com.favtuts.io.utils.FileResourcesUtils.main(FileResourcesUtils.java:24)
- # for new File(resource.toURI());
- getResource : json/file1.json
- Exception in thread "main" java.lang.IllegalArgumentException: URI is not hierarchical
- at java.base/java.io.File.
(File.java:420) - at com.favtuts.io.utils.FileResourcesUtils.getFileFromResource(FileResourcesUtils.java:112)
- at com.favtuts.io.utils.FileResourcesUtils.main(FileResourcesUtils.java:29)
您可能会收到以下消息
no main manifest attribute, in "java-io.jar"
要解决此问题,请阅读堆栈溢出:无法执行 jar 文件:“无主清单属性”中的指南
对于 Maven,我们应该使用在 pom 中定义的 maven-jar 插件.xml:
-
- <plugin>
- <groupId>org.apache.maven.pluginsgroupId>
- <artifactId>maven-jar-pluginartifactId>
- <version>3.2.0version>
- <configuration>
- <excludes>
- <exclude>**/log4j.propertiesexclude>
- excludes>
- <archive>
- <manifest>
- <addClasspath>trueaddClasspath>
- <mainClass>com.favtuts.io.utils.FileResourcesUtilsmainClass>
- <classpathPrefix>dependency-jars/classpathPrefix>
- manifest>
- archive>
- configuration>
- plugin>
附言:此示例使用 Maven 插件创建 JAR 文件。
要检查 jar 文件中的主类,请执行以下操作:
$ jar tf target/java-io.jar | more
3.1 我们将测试资源放在单元测试的src/test/resources文件夹中。通常,测试资源中的文件将复制到target/test-classes文件夹。

src/test/resources/json/file1.json
- {
- "name": "unit test",
- "age": 38
- }
src/test/resources/database.properties.properties
- datasource.url=jdbc:mysql://localhost/test?useSSL=false
- datasource.username=test
- datasource.password=password
- datasource.driver-class-name=com.mysql.jdbc.Driver
3.2 它的工作方式与我们从src/main/resources中读取文件的方式相同。我们使用相同的getResourceAsStream和getResource方法从 src/test/resources读取文件.
FileResourcesTest.java
- package com.favtuts.io;
-
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.net.URISyntaxException;
- import java.net.URL;
- import java.nio.charset.StandardCharsets;
- import java.nio.file.Files;
- import java.util.List;
-
- import org.junit.jupiter.api.DisplayName;
- import org.junit.jupiter.api.Test;
-
- // Unit test class
- public class FileResourcesTest {
-
- @DisplayName("Test loading a JSON file")
- @Test
- void loadJSONTest() {
-
- String fileName = "json/file1.json";
-
- ClassLoader classLoader = getClass().getClassLoader();
-
- try (InputStream inputStream = classLoader.getResourceAsStream(fileName);
- InputStreamReader streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
- BufferedReader reader = new BufferedReader(streamReader)
- ) {
-
- String line;
- while((line = reader.readLine()) != null) {
- System.out.println(line);
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
-
- @DisplayName("Test loading a properties file")
- @Test
- void loadPropTest() throws IOException, URISyntaxException {
-
- String fileName = "database.properties";
-
- ClassLoader classLoader = getClass().getClassLoader();
-
- URL resource = classLoader.getResource(fileName);
- if (resource == null) {
- throw new IllegalArgumentException("file not found! " + fileName);
- }
-
- //File file = new File(resource.getFile());
- File file = new File(resource.toURI());
-
- List
lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8); - lines.forEach(System.out::println);
- }
-
- }
输出
- {
- "name": "unit test",
- "age": 38
- }
- datasource.url=jdbc:mysql://localhost/test?useSSL=false
- datasource.username=test
- datasource.password=password
- datasource.driver-class-name=com.mysql.jdbc.Driver
如果我们不知道确切的文件名,并且想要读取所有文件,包括资源文件夹中的子文件夹文件,我们可以使用NIO Files.walk轻松访问和读取文件。
4.1 以下示例使用Files.walk从src/main/resources/json文件夹中读取所有文件:
FileResourcesUtils.java
- package com.favtuts.io.utils;
-
- import java.io.*;
- import java.net.URISyntaxException;
- import java.net.URL;
- import java.nio.charset.StandardCharsets;
- import java.nio.file.Files;
- import java.nio.file.Paths;
- import java.util.List;
- import java.util.stream.Collectors;
-
- public class FileResourcesUtils {
-
- public static void main(String[] args) throws IOException {
-
- FileResourcesUtils app = new FileResourcesUtils();
-
- // read all files from a resources folder
- try {
-
- // files from src/main/resources/json
- List
result = app.getAllFilesFromResource("json"); - for (File file : result) {
- System.out.println("file : " + file);
- printFile(file);
- }
-
- } catch (URISyntaxException | IOException e) {
- e.printStackTrace();
- }
-
- }
-
- private List
getAllFilesFromResource(String folder) - throws URISyntaxException, IOException {
-
- ClassLoader classLoader = getClass().getClassLoader();
-
- URL resource = classLoader.getResource(folder);
-
- // dun walk the root path, we will walk all the classes
- List
collect = Files.walk(Paths.get(resource.toURI())) - .filter(Files::isRegularFile)
- .map(x -> x.toFile())
- .collect(Collectors.toList());
-
- return collect;
- }
-
- // print a file
- private static void printFile(File file) {
-
- List
lines; - try {
- lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
- lines.forEach(System.out::println);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- }
输出
- file : /home/favtuts/projects/core-java/java-io/target/classes/json/file1.json
- {
- "name": "favtuts",
- "age": 38
- }
- file : /home/favtuts/projects/core-java/java-io/target/classes/json/file2.json
- {
- "name": "jack",
- "age": 40
- }
- file : /home/favtuts/projects/core-java/java-io/target/classes/json/sub/subfile1.json
- {
- "name": "sub",
- "age": 99
- }
4.2 但是,示例 4.1 中的标准Files.walk无法直接访问 JAR 文件中的文件,请尝试在 JAR 环境中运行示例 4.1,然后它会引发FileSystemNotFoundException。
- $ mvn clean package
- $ java -jar target/java-io.jar
- Exception in thread "main" java.nio.file.FileSystemNotFoundException
- at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:169)
- at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:155)
- at java.base/java.nio.file.Path.of(Path.java:208)
- at java.base/java.nio.file.Paths.get(Paths.java:97)
- at com.favtuts.io.utils.FileResourcesUtils.getAllFilesFromResource(FileResourcesUtils.java:128)
- at com.favtuts.io.utils.FileResourcesUtils.main(FileResourcesUtils.java:35)
5.1 此示例演示Files.walk如何通过FileSystems和jar:file:xxx.jar URI读取 JAR 文件内的文件夹 。
这个想法是:
FileSystems在 JAR 文件中遍历文件夹,并获取所有文件名,请参见getPathsFromResourceJAR()getFileFromResourceAsStream()FileResourcesUtils.java
- package com.favtuts.io.utils;
-
- import java.io.*;
- import java.net.URI;
- import java.net.URISyntaxException;
- import java.nio.charset.StandardCharsets;
- import java.nio.file.FileSystem;
- import java.nio.file.FileSystems;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.util.Collections;
- import java.util.List;
- import java.util.stream.Collectors;
-
- public class FileResourcesUtils {
-
- public static void main(String[] args) throws IOException {
-
- FileResourcesUtils app = new FileResourcesUtils();
-
- // Sample 3 - read all files from a resources folder (JAR version)
- try {
-
- // get paths from src/main/resources/json
- List
result = app.getPathsFromResourceJAR("json"); - for (Path path : result) {
- System.out.println("Path : " + path);
-
- String filePathInJAR = path.toString();
- // Windows will returns /json/file1.json, cut the first /
- // the correct path should be json/file1.json
- if (filePathInJAR.startsWith("/")) {
- filePathInJAR = filePathInJAR.substring(1, filePathInJAR.length());
- }
-
- System.out.println("filePathInJAR : " + filePathInJAR);
-
- // read a file from resource folder
- InputStream is = app.getFileFromResourceAsStream(filePathInJAR);
- printInputStream(is);
- }
-
- } catch (URISyntaxException | IOException e) {
- e.printStackTrace();
- }
-
- }
-
- // get a file from the resources folder
- // works everywhere, IDEA, unit test and JAR file.
- private InputStream getFileFromResourceAsStream(String fileName) {
-
- // The class loader that loaded the class
- ClassLoader classLoader = getClass().getClassLoader();
- InputStream inputStream = classLoader.getResourceAsStream(fileName);
-
- // the stream holding the file content
- if (inputStream == null) {
- throw new IllegalArgumentException("file not found! " + fileName);
- } else {
- return inputStream;
- }
-
- }
-
- // Get all paths from a folder that inside the JAR file
- private List
getPathsFromResourceJAR(String folder) - throws URISyntaxException, IOException {
-
- List
result; -
- // get path of the current running JAR
- String jarPath = getClass().getProtectionDomain()
- .getCodeSource()
- .getLocation()
- .toURI()
- .getPath();
- System.out.println("JAR Path :" + jarPath);
-
- // file walks JAR
- URI uri = URI.create("jar:file:" + jarPath);
- try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
- result = Files.walk(fs.getPath(folder))
- .filter(Files::isRegularFile)
- .collect(Collectors.toList());
- }
-
- return result;
-
- }
-
- // print input stream
- private static void printInputStream(InputStream is) {
-
- try (InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8);
- BufferedReader reader = new BufferedReader(streamReader)) {
-
- String line;
- while ((line = reader.readLine()) != null) {
- System.out.println(line);
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- }
输出
- $ java -jar target/java-io.jar
- JAR Path :/C:/Users/favtuts/projects/core-java/java-io/target/java-io.jar
- Path : /json/file2.json
- filePathInJAR : json/file2.json
- {
- "name": "jack",
- "age": 40
- }
- Path : /json/file1.json
- filePathInJAR : json/file1.json
- {
- "name": "favtuts",
- "age": 38
- }
- Path : /json/sub/subfile1.json
- filePathInJAR : json/sub/subfile1.json
- {
- "name": "sub",
- "age": 99
- }
$ git clone https://github.com/favtuts/java-core-tutorials-examples
$ cd java-io