【问题标题】:Java: Cannot load a JPG image as a resource in a JAR fileJava:无法将 JPG 图像作为 JAR 文件中的资源加载
【发布时间】:2020-05-07 10:53:12
【问题描述】:

在下面的代码sn-p中:

InputStream inputStream = 
            ClassLoader.getSystemClassLoader()
                       .getResource("pics/logo.jpg")
                       .openStream();

getResourceopenStream 返回 null。如何缓解此问题?

【问题讨论】:

    标签: java jar nullpointerexception null embedded-resource


    【解决方案1】:

    要从*.jar 文件加载*.jpg 图像(或任何其他图像),请使用以下架构:

    1. 创建一个项目,然后编译成*.jar文件

      project-with-resources
      │
      ├── src
      │   └── main
      │       ├── java
      │       │   ├── . . .
      │       │   └── Project.java
      │       └── resources
      │           ├── . . .
      │           └── image1.jpg
      └── pom.xml
      
    2. 配置maven-resources-plugin(可能有多个资源文件夹)

      <build>
          <defaultGoal>package</defaultGoal>
          <resources>
              <resource>
                  <directory>src/main/resources</directory>
                  <targetPath>resources</targetPath>
              </resource>
              . . .
          </resources>
          <plugins>
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-resources-plugin</artifactId>
                  <version>3.1.0</version>
              </plugin>
              . . .
          </plugins>
      </build>
      
    3. Java 代码中使用ImageIO 类将图片读入BufferedImage 对象

      public class Project {
          public static void main(String[] args) throws IOException {
              BufferedImage image =
                  ImageIO.read(Project.class
                      .getResourceAsStream("/resources/image1.jpg"));
          }
      }
      
    4. 如有必要,准备吸气剂

      public class Project {
          private BufferedImage image;
          . . .
          public BufferedImage getImage() {
              return image;
          }
      }
      
    5. 在您的 IDE 中使用 Maven package 目标将项目构建到 *.jar 文件

    【讨论】:

      【解决方案2】:

      你需要把'logo.jpg'放在'pics'目录下,相对于你的CLASSPATH的根目录,否则ClassLoader.getResource()会返回null,当你尝试打开一个基于它。

      因此,使用带有此代码的 Eclipse 工作区...

      import java.io.InputStream;
      import java.net.URL;
      
      public class GetResource {
          public static void main(String[] args) throws Exception {
              ClassLoader classLoader = ClassLoader.getSystemClassLoader();
              URL resource = classLoader.getResource("pics/logo.jpg");
              System.out.println("resource is " + resource);
              InputStream inputStream = resource.openStream();
              System.out.println("The inputStream was not null");
          }
      }
      

      它会返回...

      resource is null
      Exception in thread "main" java.lang.NullPointerException
          at GetResource.main(GetResource.java:9)
      

      如果找不到相对于 CLASSPATH 根目录的“pics/logo.jpg”。在正确的位置创建“logo.jpg”文件(这里是Eclipse项目的“src/pics”文件夹,会自动放入“bin/pics”文件夹),输出为...

      resource is file:/home/joe/workspace/Play/bin/pics/logo.jpg
      The inputStream was not null
      

      通常资源会捆绑在您的 jar 中,因此“logo.jpg”应位于 jar 根目录下的“/pics”目录中。

      【讨论】:

      • 没有必要像那样使用类加载器。只需使用GetResource.class.getResource()。有几种方法会导致类加载器版本失败,而仅使用 ClassName.class 不会。
      【解决方案3】:

      根据您的应用程序是否使用 SecurityManager 及其安全策略运行,您可能没有足够的权限。

      如果我没看错Manual

      它还为您所使用的不同方法之间的细微差别提供了指导和解释。

      【讨论】:

        【解决方案4】:

        java.lang.Class.getResource()java.lang.ClassLoader.getResource() 对资源名称的解释有所不同:首先,给定的名称是相对于类的包的,除非它以'/'开头,给定的名称是第二个总是“绝对的”。

        这意味着当您调用java.lang.String.class.getResource( "resource/Doc.jpg" ) 时,它会寻找/java/lang/resource/Doc.jpg,而对java.lang.String.class.getClassLoader().getResource( "resource/Doc.jpg" ) 的调用会尝试找到/resource/Doc.jpg

        两者都不是真正的“路径”(就文件系统上的位置而言),它们确定相对于 CLASSPATH 的位置。 可以是文件系统上的一个位置(如果资源不在 JAR 文件中……),但它也可以是对数据库记录的引用,以 URI 的形式提供,具体取决于实现所涉及的类加载器。

        【讨论】:

          【解决方案5】:

          我在 Netbeans 中创建了一个带有 Ant 的 Java 应用程序:

          public class Main {
              public static void main(String[] args){
                  System.out.println(ClassLoader.getSystemClassLoader().
                          getResource(".").getPath());
              }
          }
          

          当我从 Netbeans 中运行它时,我得到了:

          /Users/enta/NetBeansProjects/JavaFrontEnd/JavaApplication47/build/classes/

          但是如果我从命令行运行它

          java -jar "/Users/enta/NetBeansProjects/JavaFrontEnd/JavaApplication50/dist/JavaApplication50.jar"

          我明白了

          线程“main”中的异常 java.lang.NullPointerException at Main.main(Main.java:13)

          奇怪;我没有深究。然后,我使用完全相同的代码在 Netbeans 中创建了一个带有 Maven 应用程序的 Java,当我在 Netbeans 内部和外部运行它时,我得到了正确的答案。从 Netbeans 内部:

          ------------------------------------------------------------------------
          Building JavaApplication46 1.0-SNAPSHOT
          ------------------------------------------------------------------------
          
          --- exec-maven-plugin:1.5.0:exec (default-cli) @ JavaApplication46 ---
          /Users/enta/NetBeansProjects/JavaFrontEnd/JavaApplication46/target/classes/
          ------------------------------------------------------------------------
          

          从命令行:

          根据路径了解您所在的位置应该有助于您将资源放置在正确的位置。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-10-11
            • 2018-03-26
            • 1970-01-01
            • 1970-01-01
            • 2011-05-12
            • 2016-12-30
            • 1970-01-01
            相关资源
            最近更新 更多