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

在Java中,我们可以使用getResourceAsStreamgetResource从​​​​​​​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.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/classesbuild/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. 从资源文件夹中获取文件。

2.1 下面的示例演示如何使用getResourceAsStreamgetResource方法从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<String> 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将失败并返回NoSuchFileExceptionInvalidPathException。我们无法通过资源 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.<init>(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:

        <!-- Make this jar executable -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.2.0</version>
          <configuration>
              <excludes>
                  <exclude>**/log4j.properties</exclude>
              </excludes>
              <archive>
                  <manifest>
                      <addClasspath>true</addClasspath>                                            
                      <mainClass>com.favtuts.io.utils.FileResourcesUtils</mainClass>                      
                      <classpathPrefix>dependency-jars/</classpathPrefix>
                  </manifest>
              </archive>
          </configuration>
        </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

{
  "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中读取文件的方式相同。我们使用相同的getResourceAsStreamgetResource方法从 ​​​​​​​​​​​​​​​​​​​​​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<String> 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

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

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

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

FileResourcesUtils.java

p
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<File> result = app.getAllFilesFromResource("json");
            for (File file : result) {
                System.out.println("file : " + file);
                printFile(file);
            }

        } catch (URISyntaxException | IOException e) {
            e.printStackTrace();
        }

    }

    private List<File> 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<File> 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<String> 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. 从资源文件夹中获取所有文件。(JAR 版本)

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

这个想法是:

  • 文件使用FileSystems在 JAR 文件中遍历文件夹,并获取所有文件名,请参见​​​​​​​getPathsFromResourceJAR()
  • 循环所有文件名,访问并打印每个文件,如示例 2.1,请参阅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<Path> 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<Path> getPathsFromResourceJAR(String folder)
        throws URISyntaxException, IOException {

        List<Path> 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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Java的File类来实现从多个文件夹随机读取1000个文件的操作。以下是实现的步骤: 1. 定义一个存储文件路径的数组,包含多个文件夹的路径。 2. 使用一个循环遍历每个文件夹,使用File类的listFiles()方法获取文件夹的所有文件。 3. 将获取到的文件路径存储到一个ArrayList。 4. 使用Collections.shuffle()方法将ArrayList文件路径随机排序。 5. 使用一个循环遍历ArrayList,根据文件路径读取文件内容。 6. 当读取的文件数量达到1000时,停止循环。 以下是示例代码: ```java import java.io.*; import java.util.*; public class RandomFileReader { public static void main(String[] args) { String[] folders = { "/path/to/folder1", "/path/to/folder2", "/path/to/folder3" }; ArrayList<String> files = new ArrayList<String>(); for (String folder : folders) { File[] folderFiles = new File(folder).listFiles(); for (File file : folderFiles) { if (file.isFile()) { files.add(file.getPath()); } } } Collections.shuffle(files); int count = 0; for (String filePath : files) { try { BufferedReader reader = new BufferedReader(new FileReader(filePath)); String line = reader.readLine(); while (line != null) { // 读取文件内容,可以根据具体需求进行处理 System.out.println(line); line = reader.readLine(); } reader.close(); count++; if (count >= 1000) { break; } } catch (IOException e) { e.printStackTrace(); } } } } ``` 需要注意的是,该代码只是简单地读取文件内容并输出到控制台。如果需要进行其他操作,可以根据具体需求进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值