Java资源作为文件


122

Java中是否有办法在通过类加载器从jar检索的资源上构造File实例?

我的应用程序使用jar(默认)或运行时指定的文件系统目录(用户输入)中的某些文件。我正在寻找一种一致的方式
a)将这些文件作为流加载
b)分别列出用户定义的目录或jar中的目录中的文件

编辑:显然,理想的方法是完全远离java.io.File。有没有办法从类路径加载目录并列出其内容(包含在其中的文件/实体)?

Answers:


58

ClassLoader.getResourceAsStream并且Class.getResourceAsStream绝对是加载资源数据的方法。但是,我不相信有任何“列出”类路径元素内容的方法。

在某些情况下,这可能根本不可能-例如,a ClassLoader 可以根据要求的资源名称即时生成数据。如果看一下ClassLoaderAPI(基本上是类路径机制的工作原理),您会发现没有任何事情可以做。

如果您知道确实有一个jar文件,可以将其加载ZipInputStream以查找可用的文件。这将意味着您将为目录和jar文件使用不同的代码。

如果首先分别创建文件,则一种替代方法是包括一种清单文件,其中包含可用资源列表。将其捆绑在jar文件中或将其作为文件包含在文件系统中,并在为用户提供选择资源之前加载它。


3
我同意这很烦人-但它使ClassLoader在其他方面更广泛地适用。例如,编写“ Web类加载器”很容易,因为Web可以很好地获取文件,但通常不会列出文件。
乔恩·斯基特

似乎如果您尝试加载的资源比1MiB大得多,InputStream那么从getResourceAsStream站点获取的资源将在该大小后检索该字节,如果包含在压缩文件系统(如jar)中,则返回0。getResource在这种情况下,您似乎被迫独立使用和加载文件。
mgttlinger 2015年

1
@mgttlinger:对我来说这听起来不太可能...如果可以的话,可能值得发布一个带有repro的新问题。
乔恩·斯基特

问题是由于read决定读取多少数据的方法(我不知道这一点)。如果正在读取的文件位于常规文件夹中,则似乎已读取了整个文件。如果该文件由于已打包而位于jar中,则仅读取其中的一部分。
mgttlinger

1
@mgttlinger:不,它不仅会读取其中的一部分,而且可能不会填充每个读取调用中提供的整个缓冲区。像往常一样InputStream,如果要读取整个资源,则应循环执行直到read返回-1。
乔恩·斯基特

98

我遇到了同样的问题,可以使用以下内容:

// Load the directory as a resource
URL dir_url = ClassLoader.getSystemResource(dir_path);
// Turn the resource into a File object
File dir = new File(dir_url.toURI());
// List the directory
String files = dir.list()

45
这种方法不适用于classpath中的JAR,仅适用于文件和目录
yegor256 2011年

1
@ yegor256如果您的文件位于jar中,则可以创建一个FileSystem对象并从中获取对象Path。然后,您可以像平常一样阅读它。(见stackoverflow.com/a/22605905/1876344
mgttlinger

53

这是我的一个应用程序中的一些代码...让我知道它是否适合您的需求。如果知道要使用的文件,则可以使用此文件。

URL defaultImage = ClassA.class.getResource("/packageA/subPackage/image-name.png");
File imageFile = new File(defaultImage.toURI());

希望有帮助。


是的,但是toURI()会失败。
奥利维尔·富乔

10

在从jar检索的资源上构造File实例的可靠方法是将资源作为流复制到临时File(当JVM退出时,临时文件将被删除):

public static File getResourceAsFile(String resourcePath) {
    try {
        InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
        if (in == null) {
            return null;
        }

        File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        tempFile.deleteOnExit();

        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            //copy stream
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
        }
        return tempFile;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

4

试试这个:

ClassLoader.getResourceAsStream ("some/pkg/resource.properties");

有更多可用的方法,例如,请参见此处:http : //www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html


感谢您的答复。我知道getResourceAsStream,但我认为我不能通过它从类路径中加载目录。
曼特鲁姆

在Java目录中是一个文件(我猜是UNIX根),因此至少应该尝试一下。
topchef

我认为要列出目录中的文件,您将需要使用java.io.File。您可以使用ClassLoader.findResource查找文件,该文件返回可以传递给File的URL。
内森·沃克斯兰

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.