如何列出 JAR 文件中的文件?
我有这段代码可以从目录中读取所有文件。
File textFolder = new File("text_directory");
File [] texFiles = textFolder.listFiles( new FileFilter() {
public boolean accept( File file ) {
return file.getName().endsWith(".txt");
}
});
效果很好。它使用目录“text_directory”中以“.txt”结尾的所有文件填充数组。
如何在 JAR 文件中以类似的方式读取目录的内容?
所以我真正想做的是,列出 JAR 文件中的所有图像,这样我就可以加载它们:(
ImageIO.read(this.getClass().getResource("CompanyLogo.png"));
该方法有效,因为“CompanyLogo”是“硬编码的”,但 JAR 文件中的图像数量可能是从 10 到 200 个可变长度。)
编辑
所以我想我的主要问题是:如何知道我的主类所在的JAR 文件的名称?
当然,我可以使用 java.util.Zip 来阅读它。
我的结构是这样的:
它们就像:
my.jar!/Main.class
my.jar!/Aux.class
my.jar!/Other.class
my.jar!/images/image01.png
my.jar!/images/image02a.png
my.jar!/images/imwge034.png
my.jar!/images/imagAe01q.png
my.jar!/META-INF/manifest
现在我可以使用以下方式加载例如“images/image01.png”:
ImageIO.read(this.getClass().getResource("images/image01.png));
但只是因为我知道文件名,其余的我必须动态加载它们。
I have this code which reads all the files from a directory.
File textFolder = new File("text_directory");
File [] texFiles = textFolder.listFiles( new FileFilter() {
public boolean accept( File file ) {
return file.getName().endsWith(".txt");
}
});
It works great. It fills the array with all the files that end with ".txt" from directory "text_directory".
How can I read the contents of a directory in a similar fashion within a JAR file?
So what I really want to do is, to list all the images inside my JAR file, so I can load them with:
ImageIO.read(this.getClass().getResource("CompanyLogo.png"));
(That one works because the "CompanyLogo" is "hardcoded" but the number of images inside the JAR file could be from 10 to 200 variable length.)
EDIT
So I guess my main problem would be: How to know the name of the JAR file where my main class lives?
Granted I could read it using java.util.Zip
.
My Structure is like this:
They are like:
my.jar!/Main.class
my.jar!/Aux.class
my.jar!/Other.class
my.jar!/images/image01.png
my.jar!/images/image02a.png
my.jar!/images/imwge034.png
my.jar!/images/imagAe01q.png
my.jar!/META-INF/manifest
Right now I'm able to load for instance "images/image01.png" using:
ImageIO.read(this.getClass().getResource("images/image01.png));
But only because I know the file name, for the rest I have to load them dynamically.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
需要提一下的是,如果您已经在使用 Spring,则可以利用 PathMatchingResourcePatternResolver。
例如,从资源中的
images
文件夹中获取所有 PNG 文件Just to mention that if you are already using Spring, you can take advantage of the
PathMatchingResourcePatternResolver
.For instance to get all the PNG files from a
images
folder in resources下面是一个使用 Reflections 库通过正则表达式名称模式递归扫描类路径的示例,并添加了几个 Guava 有助于获取资源内容:
这适用于 jar 和分解类。
Here is an example of using Reflections library to recursively scan classpath by regex name pattern augmented with a couple of Guava perks to to fetch resources contents:
This works with both jars and exploded classes.
这是我为“运行包下的所有 JUnit”编写的方法。您应该能够根据您的需要进行调整。
编辑:
啊,在这种情况下,您可能也需要这个片段(相同的用例:))
Here's a method I wrote for a "run all JUnits under a package". You should be able to adapt it to your needs.
Edit:
Ah, in that case, you might want this snippet as well (same use case :) )
jar 文件只是一个带有结构化清单的 zip 文件。您可以使用常用的 java zip 工具打开 jar 文件,并以这种方式扫描文件内容、膨胀流等。然后在 getResourceAsStream 调用中使用它,这一切都应该很顺利。
编辑/澄清后
我花了一分钟的时间来记住所有的点点滴滴,我确信有更干净的方法来做到这一点,但我想看看我没有疯。在我的项目中,image.jpg 是主 jar 文件某些部分中的一个文件。我获取主类的类加载器(SomeClass 是入口点)并使用它来发现 image.jpg 资源。然后使用一些流魔法将其放入 ImageInputStream 中,一切都很好。
A jar file is just a zip file with a structured manifest. You can open the jar file with the usual java zip tools and scan the file contents that way, inflate streams, etc. Then use that in a getResourceAsStream call, and it should be all hunky dory.
EDIT / after clarification
It took me a minute to remember all the bits and pieces and I'm sure there are cleaner ways to do it, but I wanted to see that I wasn't crazy. In my project image.jpg is a file in some part of the main jar file. I get the class loader of the main class (SomeClass is the entry point) and use it to discover the image.jpg resource. Then some stream magic to get it into this ImageInputStream thing and everything is fine.
给定一个实际的 JAR 文件,您可以使用
JarFile.entries()
列出内容。不过,您需要知道 JAR 文件的位置 - 您不能只要求类加载器列出它可以获得的所有内容。您应该能够根据
ThisClassName.class.getResource("ThisClassName.class")
返回的 URL 计算出 JAR 文件的位置,但这可能有点麻烦。Given an actual JAR file, you can list the contents using
JarFile.entries()
. You will need to know the location of the JAR file though - you can't just ask the classloader to list everything it could get at.You should be able to work out the location of the JAR file based on the URL returned from
ThisClassName.class.getResource("ThisClassName.class")
, but it may be a tiny bit fiddly.前段时间我做了一个从 JAR 内部获取类的函数:
Some time ago I made a function that gets classess from inside JAR:
有两个非常有用的实用程序都称为 JarScan:
www.inetfeedback.com/jarscan
jarscan.dev.java.net
另请参阅这个问题:JarScan,扫描所有子文件夹中的所有 JAR 文件特定类别
There are two very useful utilities both called JarScan:
www.inetfeedback.com/jarscan
jarscan.dev.java.net
See also this question: JarScan, scan all JAR files in all subfolders for specific class
目前列出类路径中所有资源的最强大的机制是 将此模式与 ClassGraph 结合使用,因为它处理 尽可能广泛的类路径规范机制,包括新的 JPMS 模块系统。 (我是 ClassGraph 的作者。)
还有许多其他处理资源的方法。
The most robust mechanism for listing all resources in the classpath is currently to use this pattern with ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author of ClassGraph.)
There are lots of other ways to deal with resources too.
另一条道路在匹配特定文件名方面更加灵活,因为它使用通配符通配符。在功能风格中,这可能类似于:
考虑参数化文件扩展名,为读者留下一个练习。
请小心
Files.walk
。根据文档:同样,newFileSystem 必须关闭,但必须在 walker 有机会访问文件系统路径之前关闭。
One more for the road that's a bit more flexible for matching specific filenames because it uses wildcard globbing. In a functional style this could resemble:
Consider parameterizing the file extensions, left an exercise for the reader.
Be careful with
Files.walk
. According to the documentation:Likewise,
newFileSystem
must be closed, but not before the walker has had a chance to visit the file system paths.只是从 jar URL 列出/读取文件的不同方式,它对嵌套 jar 递归执行
https:// gist.github.com/trung/2cd90faab7f75b3bcbaa
Just a different way of listing/reading files from a jar URL and it does it recursively for nested jars
https://gist.github.com/trung/2cd90faab7f75b3bcbaa
请注意,在 Java 7 中,您可以从 JAR (zip) 文件创建一个
FileSystem
,然后使用 NIO 的目录遍历和过滤机制来搜索它。这将使编写处理 JAR 和“分解”目录的代码变得更容易。Note that in Java 7, you can create a
FileSystem
from the JAR (zip) file, and then use NIO's directory walking and filtering mechanisms to search through it. This would make it easier to write code that handles JARs and "exploded" directories.适用于 IDE 和 .jar 文件的代码:
Code that works for both IDE's and .jar files:
埃里克森的答案工作得很好:
这是工作代码。
我刚刚将我的加载方法从以下修改
为:
erickson's answer worked perfectly:
Here's the working code.
And I have just modify my load method from this:
To this:
我想扩展 acheron55 的 答案,因为它是一个非常不安全的解决方案,原因如下:
FileSystem
对象。FileSystem
对象是否已存在。这在某种程度上是一个更安全的解决方案:
没有真正需要同步文件名;人们可以简单地每次同步同一个对象(或使方法同步),这纯粹是一种优化。
我想说这仍然是一个有问题的解决方案,因为代码中可能有其他部分在相同的文件上使用 FileSystem 接口,并且它可能会干扰它们(即使在单线程应用程序中) ).
另外,它不会检查
null
(例如,在getClass().getResource()
上)。这个特定的 Java NIO 接口有点可怕,因为它引入了全局/单例非线程安全资源,其文档非常模糊(由于提供程序特定的实现,结果可能会有所不同)其他
FileSystem
提供程序(不是 JAR)。这样做的充分理由;我不知道,我还没有研究过这些实现。I would like to expand on acheron55's answer, since it is a very non-safe solution, for several reasons:
FileSystem
object.FileSystem
object already exists.This is somewhat a safer solution:
There's no real need to synchronize over the file name; one could simply synchronize on the same object every time (or make the method
synchronized
), it's purely an optimization.I would say that this is still a problematic solution, since there might be other parts in the code that use the
FileSystem
interface over the same files, and it could interfere with them (even in a single threaded application).Also, it doesn't check for
null
s (for instance, ongetClass().getResource()
.This particular Java NIO interface is kind of horrible, since it introduces a global/singleton non thread-safe resource, and its documentation is extremely vague (a lot of unknowns due to provider specific implementations). Results may vary for other
FileSystem
providers (not JAR). Maybe there's a good reason for it being that way; I don't know, I haven't researched the implementations.假设您的项目打包在 Jar 中(不一定如此!),您可以使用 ClassLoader.getResource() 或 findResource() 以及类名(后跟 .class)来获取包含给定类的 jar。您必须从返回的 URL 中解析 jar 名称(不是那么难),我将把它作为练习留给读者:-)
请务必测试类不属于 jar 的情况。
Assuming that your project is packed in a Jar (not necessarily true!), you can use ClassLoader.getResource() or findResource() with the class name (followed by .class) to get the jar that contains a given class. You'll have to parse the jar name from the URL that gets returned (not that tough), which I will leave as an exercise for the reader :-)
Be sure to test for the case where the class is not part of a jar.
我已经移植了 acheron55 的答案 到 Java 7 并关闭
FileSystem
对象。此代码可以在 IDE、jar 文件以及 Tomcat 7 上的 war 内的 jar 中运行;但请注意,它不能在JBoss 7上的战争中的jar中工作(它给出FileSystemNotFoundException:Provider“vfs”未安装
,另请参阅这篇文章)。此外,与原始代码一样,它不是线程安全的,正如 错误。由于这些原因,我放弃了这个解决方案;但是,如果您可以接受这些问题,这里是我现成的代码:I've ported acheron55's answer to Java 7 and closed the
FileSystem
object. This code works in IDE's, in jar files and in a jar inside a war on Tomcat 7; but note that it does not work in a jar inside a war on JBoss 7 (it givesFileSystemNotFoundException: Provider "vfs" not installed
, see also this post). Furthermore, like the original code, it is not thread safe, as suggested by errr. For these reasons I have abandoned this solution; however, if you can accept these issues, here is my ready-made code: