java 从类路径资源文件夹获取文件列表?[副本]

r6l8ljro  于 2023-05-27  发布在  Java
关注(0)|答案(2)|浏览(127)

此问题已在此处有答案

Get a list of resources from classpath directory(16个回答)
1小时前关闭
我试图从资源文件夹中设置JFX ImageView图像,但似乎无法获得不会引发异常的适当URL/String文件路径。

var x = getRandomImageFromPackage("pictures").toString();
var y = getClass().getClassLoader().getResource("pictures/mindwave/active/Super Saiyan.gif").toString();
this.iconImageView.setImage(new Image(x));

x返回

/home/sarah/Desktop/Dropbox/School/Current/MAX MSP Utilities/MindWaveMobileDataServer/target/classes/pictures/0515e3b7cb30ac92ebfe729440870a5c.jpg

y返回的内容如下:

file:/home/sarah/Desktop/Dropbox/School/Current/MAX%20MSP%20Utilities/MindWaveMobileDataServer/target/classes/pictures/mindwave/active/Super%20Saiyan.gif

理论上,这两种情况都是可以接受的,但是,如果x被放置在下面的setImage(String)行中,则只有x会抛出异常。
有没有办法得到包中的图像列表,以便我可以随机选择一个并设置ImageView?
我知道有一个自定义扫描仪选项,但它看起来相当过时(超过11岁,当时并没有真正支持):

常规:

/**
 * Gets a picture from the classpath pictures folder.
 *
 * @param packageName The string path (in package format) to the classpath
 * folder
 * @return The random picture
 */
private Path getRandomImageFromPackage(String packageName) {
    try {
        var list = Arrays.asList(new File(Thread.currentThread().getContextClassLoader().getResource(packageName)
                .toURI()).listFiles());
        var x = list.get(new Random().nextInt(list.size())).toString();
        return list.get(new Random().nextInt(list.size())).toPath();

    } catch (URISyntaxException ex) {
        throw new IllegalStateException("Encountered an error while trying to get a picture from the classpath"
                + "filesystem", ex);
    }
}

作为参考,这是资源文件夹:

mrwjdhj3

mrwjdhj31#

您的方法问题

  • 您没有格式正确的URL*

new Image(String url)以url作为参数。
空格不是URL的有效字符:

这就是为什么你的x字符串不是一个有效的URL,不能用于构造图像。

  • 您需要提供Image构造函数可识别的输入 *

请注意,它稍微复杂一些,因为从Image javadoc开始,url参数可以是直接url以外的东西,但即使如此,它们也不匹配您试图查找的内容。
如果一个URL字符串被传递给一个构造函数,它可以是以下任何一种:
1.可由该线程的上下文ClassLoader解析的资源的名称
1.可由文件解析的文件路径
1.可以通过URL解析且存在协议处理程序的URL
除了为应用程序注册的协议处理程序外,还支持URL的RFC 2397“数据”方案。如果URL使用“data”方案,则数据必须是base64编码的,并且MIME类型必须为空或图像类型的子类型。

  • 您假设资源位于文件系统中,但这并不总是有效 *

如果你把你的资源打包到一个jar里,那么这将不起作用:

Arrays.asList(
    new File(
        Thread.currentThread()
            .getContextClassLoader()
            .getResource(packageName)
            .toURI()
    ).listFiles()
);

这不起作用,因为jar中的文件是使用jar:协议而不是file:协议定位的。因此,您将无法从getResource返回的jar:协议URI创建File对象。

推荐方法:使用Spring

从jar中获取资源列表实际上是一件相当棘手的事情。从你链接的问题,最简单的解决方案是一个使用

不幸的是,这意味着需要依赖Spring框架才能使用它,这对于这项任务来说完全是多余的。. .... .然而,我不知道任何其他简单的鲁棒解决方案。但至少你可以只调用Spring实用程序类,你不需要启动整个Spring依赖注入容器来使用它,所以你根本不需要知道任何Spring或承受任何Spring开销。
所以,你可以写这样的东西(ResourceLister是我创建的一个类,以及toURL方法,请参阅示例应用程序):

public List<String> getResourceUrls(String locationPattern) throws IOException {
    ClassLoader classLoader = ResourceLister.class.getClassLoader();
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader);

    Resource[] resources = resolver.getResources(locationPattern);

    return Arrays.stream(resources)
            .map(this::toURL)
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
}

可执行示例

  • ResourceLister.java*
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

public class ResourceLister {
    // currently, only gets pngs, if needed, can add
    // other patterns and union the results to get 
    // multiple image types. 
    private static final String IMAGE_PATTERN =
            "classpath:/img/*.png";

    public List<String> getImageUrls() throws IOException {
        return getResourceUrls(IMAGE_PATTERN);
    }

    public List<String> getResourceUrls(String locationPattern) throws IOException {
        ClassLoader classLoader = ResourceLister.class.getClassLoader();
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader);

        Resource[] resources = resolver.getResources(locationPattern);

        return Arrays.stream(resources)
                .map(this::toURL)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    private String toURL(Resource r) {
        try {
            if (r == null) {
                return null;
            }

            return r.getURL().toExternalForm();
        } catch (IOException e) {
            return null;
        }
    }

    public static void main(String[] args) throws IOException {
        ResourceLister lister = new ResourceLister();
        System.out.println(lister.getImageUrls());
    }
}
  • AnimalApp.java*
import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

public class AnimalApp extends Application {
    private static final double ANIMAL_SIZE = 512;

    // remove the magic seed if you want a different random sequence all the time.
    private final Random random = new Random(42);

    private final ResourceLister resourceLister = new ResourceLister();

    private List<Image> images;

    @Override
    public void init() {
        List<String> imageUrls = findImageUrls();
        images = imageUrls.stream()
                .map(Image::new)
                .collect(Collectors.toList());
    }

    @Override
    public void start(Stage stage) {
        ImageView animalView = new ImageView();
        animalView.setFitWidth(ANIMAL_SIZE);
        animalView.setFitHeight(ANIMAL_SIZE);
        animalView.setPreserveRatio(true);

        Button findAnimalButton = new Button("Find animal");
        findAnimalButton.setOnAction(e ->
                animalView.setImage(randomImage())
        );

        VBox layout = new VBox(10,
                findAnimalButton,
                animalView
        );
        layout.setPadding(new Insets(10));
        layout.setAlignment(Pos.CENTER);

        stage.setScene(new Scene(layout));
        stage.show();
    }

    private List<String> findImageUrls() {
        try {
            return resourceLister.getImageUrls();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return new ArrayList<>();
    }

    /**
     * Chooses a random image.
     *
     * Allows the next random image chosen to be the same as the previous image.
     *
     * @return a random image or null if no images were found.
     */
    private Image randomImage() {
        if (images == null || images.isEmpty()) {
            return null;
        }

        return images.get(random.nextInt(images.size()));
    }

    public static void main(String[] args) {
        launch(args);
    }
}
  • pom.xml*
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>resource-lister</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>resource-lister</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>5.7.1</junit.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>17.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>LATEST</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • 图片 *

放在src/main/resources/img中。

  • chicken.png
  • cow.png
  • pig.png
  • sheep.png

  • 执行命令 *

为JavaFX SDK安装设置VM参数:

-p C:\dev\javafx-sdk-17.0.2\lib --add-modules javafx.controls
ymdaylpp

ymdaylpp2#

没有简单可靠的方法来做到这一点。因此,我创建了一个清单文件并将其放入resources文件夹中。所以在运行时,我可以读取,然后有所有的文件名awailable,我需要的。
下面是一个小测试,展示了我如何创建该文件:

public class ListAppDefaultsInventory {

    @Test
    public void test() throws IOException {
        List<String> inventory = listFilteredFiles("src/main/resources/app-defaults", Integer.MAX_VALUE);
        assertFalse("Directory 'app-defaults' is empty.", inventory.isEmpty());
        System.out.println("# src/main/resources/app-defaults-inventory.txt");
        inventory.forEach(s -> System.out.println(s));
    }
    
    public List<String> listFilteredFiles(String dir, int depth) throws IOException {
        try (Stream<Path> stream = Files.walk(Paths.get(dir), depth)) {
            return stream
                .filter(file -> !Files.isDirectory(file))
                .filter(file -> !file.getFileName().toString().startsWith("."))
                .map(Path::toString)
                .map(s -> s.replaceFirst("src/main/resources/app-defaults/", ""))
                .collect(Collectors.toList());
        }
    }
    
}

相关问题