【问题标题】:Classloader and FileInputStream won't find file inside JARClassloader 和 FileInputStream 在 JAR 中找不到文件
【发布时间】:2016-10-13 09:32:19
【问题描述】:

我正在使用 maven 构建我的 jar 文件,它们包含所有依赖项,所以我可以通过运行 jar

java -jar

在 jar 中,我有一个 config.json,它是应用程序配置。 我验证了 config.json 确实在 jar 中:

/> jar tf cloudimport-0.1-jar-with-dependencies.jar | grep config.json
config.json

但是当我运行应用程序时,它找不到 config.json:

ClassLoader classLoader = getClass().getClassLoader();
System.out.println(classLoader.getResource("config.json"));
File configFile =  new File(classLoader.getResource(fileName).getFile());
(Exception thrown here ->) FileReader fileReader = new FileReader(configFile);
BufferedReader br = new BufferedReader(fileReader);

产生:

java -jar cloudimport-0.1-jar-with-dependencies.jar
jar:file:/home/ubuntu/cloudimport-0.1-jar-with-dependencies.jar!/config.json
java.io.FileNotFoundException: file:/home/ubuntu/cloudimport-0.1-jar-with-dependencies.jar!/config.json (No such file or directory)

运行上述代码的类位于jar中:

com.test.cloudsync.config.AppConfig.class

如果我在 windows 中从 intelliJ 运行应用程序,它可以正常工作,但从 intelliJ 执行意味着执行的是主类而不是 jar。

我已经搜索过这个,但答案如下: What is the difference between Class.getResource() and ClassLoader.getResource()?

没有帮助...

// 编辑 建议是 ClassLoader 没有抛出 Excpetion - 这是真的。我删除了一些东西,所以我可以限制范围,现在看来问题是我尝试打开 FileINputStream 但这不可能我猜文件是否带有 jar?

完整的堆栈跟踪:

/> java -jar java_cloudsync/com/tsg/cloudimport/cloudimport/0.1/cloudimport-0.1-jar-with-dependencies.jar   
jar:file:/home/ubuntu/java_cloudsync/com/tsg/cloudimport/cloudimport/0.1/cloudimport-0.1-jar-with-dependencies.jar!/config.json
    java.io.FileNotFoundException: file:/home/ubuntu/java_cloudsync/com/tsg/cloudimport/cloudimport/0.1/cloudimport-0.1-jar-with-dependencies.jar!/config.json (No such file or directory)
            at java.io.FileInputStream.open0(Native Method)
            at java.io.FileInputStream.open(FileInputStream.java:195)
            at java.io.FileInputStream.<init>(FileInputStream.java:138)
            at java.io.FileReader.<init>(FileReader.java:72)
            at com.tsg.cloudsync.config.AppConfig.readConfigFile(AppConfig.java:33)
            at com.tsg.cloudsync.config.AppConfig.<init>(AppConfig.java:23)
            at com.tsg.cloudsync.awsutils.SQSSocket.<init>(SQSSocket.java:34)
            at com.tsg.cloudsync.awsutils.SQSSocket.<clinit>(SQSSocket.java:19)
            at com.tsg.cloudsync.NewFileWatchDog.main(NewFileWatchDog.java:24)
    Exception in thread "main" java.lang.ExceptionInInitializerError
            at com.tsg.cloudsync.NewFileWatchDog.main(NewFileWatchDog.java:24)
    Caused by: java.lang.NullPointerException
            at com.tsg.cloudsync.config.AppConfig.getAWSCredentials(AppConfig.java:50)
            at com.tsg.cloudsync.awsutils.SQSSocket.<init>(SQSSocket.java:35)
            at com.tsg.cloudsync.awsutils.SQSSocket.<clinit>(SQSSocket.java:19)
            ... 1 more

【问题讨论】:

  • 尝试使用getResource("/config.json") -> 请注意资源名称前的/
  • 您能否发布以java.io.FileNotFoundException 失败的代码。根据System.out.println(classLoader.getResource("config.json"))打印的jar:file:/home/ubuntu/cloudimport-0.1-jar-with-dependencies.jar!/config.json行,您已经证明可以找到该文件。
  • 我删除了一些东西,可能会限制异常,有关详细信息,请参阅我的编辑。似乎无法读取输入流,因为文件在我猜的 jar 内?

标签: java jar


【解决方案1】:

原来我是在尝试定义一个

ClassLoader classLoader = getClass().getClassLoader();
File f = new File(classLoader.getResource(fileName).getFile())
FileReader fileReader = new FileReader(configFile);
BufferedReader br = new BufferedReader(fileReader);

这是不可能的,因为 jar 本身就是一个文件。 所以改为获取文件的内容:

ClassLoader classLoader = getClass().getClassLoader();
InputStream in = classLoader.getResourceAsStream(fileName);
BufferedReader br = new BufferedReader(new InputStreamReader(in));

也可以参考这里: Reading a resource file from within jar

注意getResourceAsStream(fileName)getResource(fileName).getFile() 的区别

感谢您为我指明正确的方向!

【讨论】:

    【解决方案2】:

    假设以下简单结构

    bin/
    src/AppConfig.java
    src/config.json
    src/manifest.mf
    

    AppConfig.java

    package com.test.cloudsync;
    public class AppConfig {
        void check() {
            ClassLoader classLoader = getClass().getClassLoader();
            System.out.println(classLoader.getResource("config.json"));
        }
        public static void main(String[] args) {
            new AppConfig().check();
        }
    }
    

    ma​​nifest.mf

    Main-Class: com.test.cloudsync.AppConfig
    

    编译并构建 Jar 文件

    javac -d bin/ src/*.java
    cp src/config.json bin/config.json
    jar cfm test.jar src/manifest.mf -C bin/ .
    

    运行罐子

    java -jar test.jar
    

    输出

    jar:file:/tmp/foobar/test.jar!/config.json
    

    这表明ClassLoader classLoader = getClass().getClassLoader()这一行没有引发异常

    【讨论】:

    • 感谢您的回答,问题似乎是我尝试根据该路径打开 FileInputStream,这似乎是不可能的,因为该文件位于 Jar 中。
    • 那是因为 URL 使用了jar 协议。从URL 获取输入流的最简单方法就是调用URL.openConnection().getInputStream()
    • 你的方法和getResourceAsStream(fileName)有什么区别;谢谢
    猜你喜欢
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多