如何从 jar 文件中访问资源文件夹中的文件夹?

我有一个资源文件夹/包在我的项目的根,我“不”想加载某个文件。如果我想加载某个文件,我会使用 class.getResourceAsStream,这样就可以了! !我实际上想做的是在资源文件夹中加载一个“文件夹”,循环在该文件夹中的文件,并得到一个文件流到每个文件并读取其中的内容... 假设文件名没有在运行前确定... 我应该怎么做?是否有一种方法可以获得文件夹中的文件列表在您的 jar 文件? 注意,包含资源的 Jar 文件与运行代码的 Jar 文件相同..。

167831 次浏览

试试以下方法。
例如,如果你的类路径是 com.abc.package.MyClass,你的资源文件在 src/com/abc/package/resources/:

URL url = MyClass.class.getResource("resources/");
if (url == null) {
// error - missing folder
} else {
File dir = new File(url.toURI());
for (File nextFile : dir.listFiles()) {
// Do something with nextFile
}
}

你也可以用

URL url = MyClass.class.getResource("/com/abc/package/resources/");

最终,我找到了解决办法:

final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());


if(jarFile.isFile()) {  // Run with JAR file
final JarFile jar = new JarFile(jarFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
while(entries.hasMoreElements()) {
final String name = entries.nextElement().getName();
if (name.startsWith(path + "/")) { //filter according to the path
System.out.println(name);
}
}
jar.close();
} else { // Run with IDE
final URL url = Launcher.class.getResource("/" + path);
if (url != null) {
try {
final File apps = new File(url.toURI());
for (File app : apps.listFiles()) {
System.out.println(app);
}
} catch (URISyntaxException ex) {
// never happens
}
}
}

第二个块只在 IDE 上运行应用程序时起作用(不使用 jar 文件) ,如果您不喜欢,可以删除它。

简单... ... 使用 OSGi。在 OSGi 中,您可以使用 findEntry 和 findPath 迭代 Bundle 的条目。

在我的 jar 文件中,我有一个名为 Upload 的文件夹,这个文件夹中还有其他三个文本文件,我需要有一个完全相同的文件夹和 jar 文件之外的文件,我使用了下面的代码:

URL inputUrl = getClass().getResource("/upload/blabla1.txt");
File dest1 = new File("upload/blabla1.txt");
FileUtils.copyURLToFile(inputUrl, dest1);


URL inputUrl2 = getClass().getResource("/upload/blabla2.txt");
File dest2 = new File("upload/blabla2.txt");
FileUtils.copyURLToFile(inputUrl2, dest2);


URL inputUrl3 = getClass().getResource("/upload/blabla3.txt");
File dest3 = new File("upload/Bblabla3.txt");
FileUtils.copyURLToFile(inputUrl3, dest3);

我知道这是很多年前的事了,但只是对于其他人来说,碰到这个话题。 您可以对目录路径使用 getResourceAsStream()方法,并且输入 Stream 将具有该目录中的所有文件名。之后,您可以将目录路径与每个文件名连接起来,并在循环中为每个文件调用 getResourceAsStream。

当我试图从 jar 中打包的资源加载一些 hadoop 配置时,我遇到了同样的问题... 在 IDE 和 jar (发行版)上都是如此。

我发现 java.nio.file.DirectoryStream最适合在本地文件系统和 jar 上迭代目录内容。

String fooFolder = "/foo/folder";
....


ClassLoader classLoader = foofClass.class.getClassLoader();
try {
uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
throw new FooException(e.getMessage());
} catch (NullPointerException e){
throw new FooException(e.getMessage());
}


if(uri == null){
throw new FooException("something is wrong directory or files missing");
}


/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
/** jar case */
try{
URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
//jar.toString() begins with file:
//i want to trim it out...
Path jarFile = Paths.get(jar.toString().substring("file:".length()));
FileSystem fs = FileSystems.newFileSystem(jarFile, null);
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
for(Path p: directoryStream){
InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
performFooOverInputStream(is);
/** your logic here **/
}
}catch(IOException e) {
throw new FooException(e.getMessage());
}
}
else{
/** IDE case */
Path path = Paths.get(uri);
try {
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
for(Path p : directoryStream){
InputStream is = new FileInputStream(p.toFile());
performFooOverInputStream(is);
}
} catch (IOException _e) {
throw new FooException(_e.getMessage());
}
}

另一种解决方案,你可以像这样使用 ResourceLoader:

import org.springframework.core.io.Resource;
import org.apache.commons.io.FileUtils;


@Autowire
private ResourceLoader resourceLoader;


...


Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
load(fi.next())
}

下面的代码将所需的“文件夹”作为 Path 返回,而不管它是否位于 jar 中。

  private Path getFolderPath() throws URISyntaxException, IOException {
URI uri = getClass().getClassLoader().getResource("folder").toURI();
if ("jar".equals(uri.getScheme())) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
return fileSystem.getPath("path/to/folder/inside/jar");
} else {
return Paths.get(uri);
}
}

需要 java 7 + 。

正如其他答案所指出的,一旦资源位于 jar 文件中,事情就会变得非常糟糕。在我们的案例中,这个解决方案是:

Https://stackoverflow.com/a/13227570/516188

在测试中工作得非常好(因为当测试运行时,代码没有打包在 jar 文件中) ,但是当应用程序实际上正常运行时就不工作了。所以我所做的是... 我硬编码应用程序中的文件列表,但我有一个从磁盘读取实际列表的测试(可以这样做,因为这在测试中工作) ,如果实际列表不匹配的列表应用程序返回失败。

这样,我在我的应用程序中有简单的代码(没有技巧) ,还有我肯定我没有忘记添加一个新的条目在列表中感谢测试。

下面的代码从自定义资源目录获取.yaml 文件。

ClassLoader classLoader = this.getClass().getClassLoader();
URI uri = classLoader.getResource(directoryPath).toURI();
    

if("jar".equalsIgnoreCase(uri.getScheme())){
Pattern pattern = Pattern.compile("^.+" +"/classes/" + directoryPath + "/.+.yaml$");
log.debug("pattern {} ", pattern.pattern());
ApplicationHome home = new ApplicationHome(SomeApplication.class);
JarFile file = new JarFile(home.getSource());
Enumeration<JarEntry>  jarEntries = file.entries() ;
while(jarEntries.hasMoreElements()){
JarEntry entry = jarEntries.nextElement();
Matcher matcher = pattern.matcher(entry.getName());
if(matcher.find()){
InputStream in =
file.getInputStream(entry);
//work on the stream
    

    

}
}
    

}else{
//When Spring boot application executed through Non-Jar strategy like through IDE or as a War.
    

String path = uri.getPath();
File[] files = new File(path).listFiles();
               

for(File file: files){
if(file != null){
try {
InputStream is = new FileInputStream(file);
//work on stream
                            

} catch (Exception e) {
log.error("Exception while parsing file yaml file {} : {} " , file.getAbsolutePath(), e.getMessage());
}
}else{
log.warn("File Object is null while parsing yaml file");
}
}
}
             

如果使用 Spring,则可以使用 org.springframework.core.io.support.PathMatchingResourcePatternResolver并处理 Resource对象而不是文件。这在 Jar 文件内部和外部运行时都可以工作。

PathMatchingResourcePatternResolver r = new PathMatchingResourcePatternResolver();
Resource[] resources = r.getResources("/myfolder/*");

然后可以使用 getInputStream和来自 getFilename的文件名访问数据。

注意,如果从 Jar 运行时尝试使用 getFile,它仍然会失败。