java—从jar中读取资源文件

yacmzcpb  于 2021-06-29  发布在  Java
关注(0)|答案(15)|浏览(514)

我想从我的jar中读取一个资源,如下所示:

File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));

//Read the file

在eclipse中运行它时,它工作得很好,但是如果我将它导出到一个jar中运行它,就会出现一个illegalargumentexception:

Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical

我真的不知道为什么但是通过测试我发现如果我改变了

file = new File(getClass().getResource("/file.txt").toURI());

file = new File(getClass().getResource("/folder/file.txt").toURI());

然后它的工作方式正好相反(它在jar中工作,但在eclipse中不工作)。
我使用的是eclipse,文件所在的文件夹位于类文件夹中。

xt0899hw

xt0899hw1#

这段代码可以在eclipse和导出的runnable jar中使用

private String writeResourceToFile(String resourceName) throws IOException {
    File outFile = new File(certPath + File.separator + resourceName);

    if (outFile.isFile())
        return outFile.getAbsolutePath();

    InputStream resourceStream = null;

    // Java: In caso di JAR dentro il JAR applicativo 
    URLClassLoader urlClassLoader = (URLClassLoader)Cypher.class.getClassLoader();
    URL url = urlClassLoader.findResource(resourceName);
    if (url != null) {
        URLConnection conn = url.openConnection();
        if (conn != null) {
            resourceStream = conn.getInputStream();
        }
    }

    if (resourceStream != null) {
        Files.copy(resourceStream, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        return outFile.getAbsolutePath();
    } else {
        System.out.println("Embedded Resource " + resourceName + " not found.");
    }

    return "";
}
hivapdat

hivapdat2#

问题是某些第三方库需要文件路径名而不是输入流。大多数答案都没有涉及这个问题。
在这种情况下,一种解决方法是将资源内容复制到临时文件中。下面的示例使用junit的 TemporaryFolder .

private List<String> decomposePath(String path){
        List<String> reversed = Lists.newArrayList();
        File currFile = new File(path);
        while(currFile != null){
            reversed.add(currFile.getName());
            currFile = currFile.getParentFile();
        }
        return Lists.reverse(reversed);
    }

    private String writeResourceToFile(String resourceName) throws IOException {
        ClassLoader loader = getClass().getClassLoader();
        InputStream configStream = loader.getResourceAsStream(resourceName);
        List<String> pathComponents = decomposePath(resourceName);
        folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
        File tmpFile = folder.newFile(resourceName);
        Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
        return tmpFile.getAbsolutePath();
    }
gmxoilav

gmxoilav3#

我找到了解决办法

BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));

将“main”替换为编码它的java类。用jar文件中的路径替换“path”。
例如,如果将state1.txt放在包com.issac.state中,那么如果运行linux或mac,则键入路径为“/com/issac/state/state1”。如果运行windows,请键入路径“\com\issac\state\state1”。除非发生“找不到文件”异常,否则不要向文件中添加.txt扩展名。

63lcw9qa

63lcw9qa4#

因为某种原因 classLoader.getResource() 当我将web应用程序部署到wildfly 14时,总是返回null。正在从获取classloader getClass().getClassLoader() 或者 Thread.currentThread().getContextClassLoader() 返回null。 getClass().getClassLoader() api医生说,
“返回类的类加载器。一些实现可能使用null来表示引导类加载器。如果这个类是由引导类装入器装入的,那么在这种实现中,这个方法将返回null。“
如果您使用的是wildfly和您的web应用程序,请尝试以下操作 request.getServletContext().getResource() 返回了资源url。这里request是servletrequest的一个对象。

csbfibhn

csbfibhn5#

要访问jar中的文件,有两个选项:
将文件放在与包名匹配的目录结构中(提取.jar文件后,它应该与.class文件位于同一目录中),然后使用 getClass().getResourceAsStream("file.txt") 将文件放在根目录下(提取.jar文件后,它应该在根目录下),然后使用 Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt") 当jar用作插件时,第一个选项可能不起作用。

taor4pac

taor4pac6#

如果您使用的是spring,则可以使用以下方法从src/main/resources读取文件:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;

  public String readFileToString(String path) throws IOException {

    StringBuilder resultBuilder = new StringBuilder("");
    ClassPathResource resource = new ClassPathResource(path);

    try (
        InputStream inputStream = resource.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {

      String line;

      while ((line = bufferedReader.readLine()) != null) {
        resultBuilder.append(line);
      }

    }

    return resultBuilder.toString();
  }
v7pvogib

v7pvogib7#

您可以使用类加载器,它将从类路径读取根路径(开头不带“/”)

InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
flseospp

flseospp8#

以下代码适用于spring boot(kotlin):

val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
xam8gpfp

xam8gpfp9#

确保使用正确的分隔符。我把所有的都换了 / 在相对路径中 File.separator . 这在ide中运行良好,但是在构建jar中不起作用。

hof1towb

hof1towb10#

到目前为止(2017年12月),这是我发现的唯一一个在ide内外都有效的解决方案。
使用pathmatchingresourcepatternresolver
注意:它也适用于Spring Boot
在本例中,我正在读取src/main/resources/my\u文件夹中的一些文件:

try {
    // Get all the files under this inner resource folder: my_folder
    String scannedPackage = "my_folder/*";
    PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
    Resource[] resources = scanner.getResources(scannedPackage);

    if (resources == null || resources.length == 0)
        log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
    else {
        for (Resource resource : resources) {
            log.info(resource.getFilename());
            // Read the file content (I used BufferedReader, but there are other solutions for that):
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                // ...
                // ...                      
            }
            bufferedReader.close();
        }
    }
} catch (Exception e) {
    throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}
gajydyqb

gajydyqb11#

与其尝试将资源作为文件寻址,不如让类加载器返回资源的inputstream,而不是通过getresourceasstream:

InputStream in = getClass().getResourceAsStream("/file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

只要 file.txt 资源在类路径上可用,那么不管 file.txt 资源处于 classes/ 目录或内部 jar .
这个 URI is not hierarchical 发生的原因是jar文件中资源的uri如下所示: file:/example.jar!/file.txt . 不能读取 jar (一) zip 文件)就像是一个普通的旧文件。
下面的答案很好地解释了这一点:
如何从javajar文件中读取资源文件?
java jar文件:使用资源错误:uri不是层次结构

bgtovc5b

bgtovc5b12#

就我而言,我终于成功了

import java.lang.Thread;
import java.io.BufferedReader;
import java.io.InputStreamReader;

final BufferedReader in = new BufferedReader(new InputStreamReader(
      Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt"))
); // no initial slash in file.txt
jei2mxaa

jei2mxaa13#

如果你想以文件的形式阅读,我相信还有一个类似的解决方案:

ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource("file/test.xml").getFile());
jei2mxaa

jei2mxaa14#

我认为这应该在java中也可以使用。我使用的以下代码正在使用kotlin。

val resource = Thread.currentThread().contextClassLoader.getResource('resources.txt')
2ul0zpep

2ul0zpep15#

我以前遇到过这个问题,我为加载做了退步。基本上第一种方法在.jar文件中工作,第二种方法在eclipse或其他ide中工作。

public class MyClass {

    public static InputStream accessFile() {
        String resource = "my-file-located-in-resources.txt";

        // this is the path within the jar file
        InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
        if (input == null) {
            // this is how we load file within editor (eg eclipse)
            input = MyClass.class.getClassLoader().getResourceAsStream(resource);
        }

        return input;
    }
}

相关问题