Java 如何列出 JAR 文件中的文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1429172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to list the files inside a JAR file?
提问by OscarRyz
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".
它工作得很好。它用目录“text_directory”中以“.txt”结尾的所有文件填充数组。
How can I read the contents of a directory in a similar fashion withina JAR file?
如何在JAR 文件中以类似的方式读取目录的内容?
So what I really want to do is, to list all the images inside my JAR file, so I can load them with:
所以我真正想做的是,列出 JAR 文件中的所有图像,以便我可以加载它们:
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.)
(那个有效是因为“CompanyLogo”是“硬编码”的,但 JAR 文件中的图像数量可能从 10 到 200 个可变长度。)
EDIT
编辑
So I guess my main problem would be: How to know the name of the JAR filewhere my main class lives?
所以我想我的主要问题是:如何知道我的主类所在的 JAR 文件的名称?
Granted I could read it using java.util.Zip
.
当然,我可以使用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:
现在我可以使用以下方法加载例如“images/image01.png”:
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.
但仅仅因为我知道文件名,其余的我必须动态加载它们。
采纳答案by erickson
CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
if (src != null) {
URL jar = src.getLocation();
ZipInputStream zip = new ZipInputStream(jar.openStream());
while(true) {
ZipEntry e = zip.getNextEntry();
if (e == null)
break;
String name = e.getName();
if (name.startsWith("path/to/your/dir/")) {
/* Do something with this entry. */
...
}
}
}
else {
/* Fail... */
}
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.
请注意,在 Java 7 中,您可以FileSystem
从 JAR (zip) 文件创建一个,然后使用 NIO 的目录遍历和过滤机制来搜索它。这将使编写处理 JAR 和“爆炸”目录的代码变得更容易。
回答by Mikeb
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.
jar 文件只是一个带有结构化清单的 zip 文件。您可以使用通常的 java zip 工具打开 jar 文件,并以这种方式扫描文件内容,扩充流等。然后在 getResourceAsStream 调用中使用它,它应该都是笨蛋。
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.
我花了一分钟来记住所有的点点滴滴,我相信有更简洁的方法来做到这一点,但我想看看我没有疯。在我的项目中,image.jpg 是主 jar 文件某些部分中的一个文件。我获取主类的类加载器(SomeClass 是入口点)并使用它来发现 image.jpg 资源。然后一些流魔法将它放入这个 ImageInputStream 东西中,一切都很好。
InputStream inputStream = SomeClass.class.getClassLoader().getResourceAsStream("image.jpg");
JPEGImageReaderSpi imageReaderSpi = new JPEGImageReaderSpi();
ImageReader ir = imageReaderSpi.createReaderInstance();
ImageInputStream iis = new MemoryCacheImageInputStream(inputStream);
ir.setInput(iis);
....
ir.read(0); //will hand us a buffered image
回答by Jon Skeet
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.
给定一个实际的 JAR 文件,您可以使用JarFile.entries()
. 不过,您需要知道 JAR 文件的位置 - 您不能只要求类加载器列出它可以获取的所有内容。
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.
您应该能够根据从 返回的 URL 计算出 JAR 文件的位置ThisClassName.class.getResource("ThisClassName.class")
,但这可能有点麻烦。
回答by Ran Biron
Here's a method I wrote for a "run all JUnits under a package". You should be able to adapt it to your needs.
这是我为“在一个包下运行所有 JUnit”而编写的方法。您应该能够使其适应您的需求。
private static void findClassesInJar(List<String> classFiles, String path) throws IOException {
final String[] parts = path.split("\Q.jar\\E");
if (parts.length == 2) {
String jarFilename = parts[0] + ".jar";
String relativePath = parts[1].replace(File.separatorChar, '/');
JarFile jarFile = new JarFile(jarFilename);
final Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
final JarEntry entry = entries.nextElement();
final String entryName = entry.getName();
if (entryName.startsWith(relativePath)) {
classFiles.add(entryName.replace('/', File.separatorChar));
}
}
}
}
Edit: Ah, in that case, you might want this snippet as well (same use case :) )
编辑:啊,在这种情况下,您可能也想要这个片段(相同的用例:))
private static File findClassesDir(Class<?> clazz) {
try {
String path = clazz.getProtectionDomain().getCodeSource().getLocation().getFile();
final String codeSourcePath = URLDecoder.decode(path, "UTF-8");
final String thisClassPath = new File(codeSourcePath, clazz.getPackage().getName().repalce('.', File.separatorChar));
} catch (UnsupportedEncodingException e) {
throw new AssertionError("impossible", e);
}
}
回答by Kevin Day
So I guess my main problem would be, how to know the name of the jar where my main class lives.
所以我想我的主要问题是,如何知道我的主要类所在的 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 :-)
假设您的项目被打包在一个 Jar 中(不一定是真的!),您可以使用 ClassLoader.getResource() 或 findResource() 和类名(后跟 .class)来获取包含给定类的 jar。您必须从返回的 URL 中解析 jar 名称(不是那么难),我将其作为练习留给读者:-)
Be sure to test for the case where the class is not part of a jar.
一定要测试类不是 jar 的一部分的情况。
回答by OscarRyz
erickson's answerworked perfectly:
埃里克森的回答完美无缺:
Here's the working code.
这是工作代码。
CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
List<String> list = new ArrayList<String>();
if( src != null ) {
URL jar = src.getLocation();
ZipInputStream zip = new ZipInputStream( jar.openStream());
ZipEntry ze = null;
while( ( ze = zip.getNextEntry() ) != null ) {
String entryName = ze.getName();
if( entryName.startsWith("images") && entryName.endsWith(".png") ) {
list.add( entryName );
}
}
}
webimages = list.toArray( new String[ list.size() ] );
And I have just modify my load method from this:
我刚刚修改了我的加载方法:
File[] webimages = ...
BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex].getName() ));
To this:
对此:
String [] webimages = ...
BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex]));
回答by jgran
There are two very useful utilities both called JarScan:
有两个非常有用的实用程序,它们都称为 JarScan:
See also this question: JarScan, scan all JAR files in all subfolders for specific class
另请参阅此问题:JarScan,扫描特定类的所有子文件夹中的所有 JAR 文件
回答by berni
Some time ago I made a function that gets classess from inside JAR:
前段时间我做了一个从 JAR 内部获取类的函数:
public static Class[] getClasses(String packageName)
throws ClassNotFoundException{
ArrayList<Class> classes = new ArrayList<Class> ();
packageName = packageName.replaceAll("\." , "/");
File f = new File(jarName);
if(f.exists()){
try{
JarInputStream jarFile = new JarInputStream(
new FileInputStream (jarName));
JarEntry jarEntry;
while(true) {
jarEntry=jarFile.getNextJarEntry ();
if(jarEntry == null){
break;
}
if((jarEntry.getName ().startsWith (packageName)) &&
(jarEntry.getName ().endsWith (".class")) ) {
classes.add(Class.forName(jarEntry.getName().
replaceAll("/", "\.").
substring(0, jarEntry.getName().length() - 6)));
}
}
}
catch( Exception e){
e.printStackTrace ();
}
Class[] classesA = new Class[classes.size()];
classes.toArray(classesA);
return classesA;
}else
return null;
}
回答by acheron55
Code that works for both IDE's and .jar files:
适用于 IDE 和 .jar 文件的代码:
import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
public class ResourceWalker {
public static void main(String[] args) throws URISyntaxException, IOException {
URI uri = ResourceWalker.class.getResource("/resources").toURI();
Path myPath;
if (uri.getScheme().equals("jar")) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
myPath = fileSystem.getPath("/resources");
} else {
myPath = Paths.get(uri);
}
Stream<Path> walk = Files.walk(myPath, 1);
for (Iterator<Path> it = walk.iterator(); it.hasNext();){
System.out.println(it.next());
}
}
}
回答by trung
Just a different way of listing/reading files from a jar URL and it does it recursively for nested jars
只是一种从 jar URL 列出/读取文件的不同方式,它对嵌套的 jar 递归执行
https://gist.github.com/trung/2cd90faab7f75b3bcbaa
https://gist.github.com/trung/2cd90faab7f75b3bcbaa
URL urlResource = Thead.currentThread().getContextClassLoader().getResource("foo");
JarReader.read(urlResource, new InputStreamCallback() {
@Override
public void onFile(String name, InputStream is) throws IOException {
// got file name and content stream
}
});