Java 为什么我的罐子没有';除非我解压缩文件,否则无法运行?

Java 为什么我的罐子没有';除非我解压缩文件,否则无法运行?,java,image,swing,jar,export,Java,Image,Swing,Jar,Export,每次我运行导出的.jar文件时,该文件包含一个JFrame,图标为图像,除非我提取该文件,否则该文件不会运行。在编译器中,它正在运行。我不想让启动器同时保存资源包和jar文件在一个目录中 “为什么我的Jar不运行,除非我提取文件?” 这似乎是对您的资源使用文件的行为。例如 File file = new File("resources/image.png"); Image image = ImagIO.read(file); 并且您可以创建项目结构(注意,resources实际上应该在src中

每次我运行导出的
.jar
文件时,该文件包含一个
JFrame
,图标为图像,除非我提取该文件,否则该文件不会运行。在编译器中,它正在运行。我不想让启动器同时保存资源包和jar文件在一个目录中

“为什么我的Jar不运行,除非我提取文件?”

这似乎是对您的资源使用
文件
的行为。例如

File file = new File("resources/image.png");
Image image = ImagIO.read(file);
并且您可以创建项目结构(注意,
resources
实际上应该在
src
中,这样它就会自动构建到jar中,除非您以不同的方式配置它。但是为了这个参数,假设您在构建到jar中的
resources
的位置配置它)

一些检查:

  • 从IDE运行-工作!为什么?使用
    File
    查找文件系统中的文件。使用相对路径,搜索将从“工作目录”开始,对于IDE,它通常位于项目根目录中。因此,
    “resources/image.png”
    是相对于
    ProjectRoot

  • 构建jar,假设它最终位于项目中的
    dist
    dir中。这就是它看起来的样子

    ProjectRoot
             dist
                ProjectRoot.jar
    
    现在为了这个参数(实际上是正确的方法),让我们尝试打印资源输入输出程序的URL,这样当您运行jar时,它会打印出文件的URL

    URL url = Test.class.getResource("/resources/image.png");
    System.out.println(url.toString());
    
    当我们运行jar
    C:\ProjectRoot\dist>java-jarprojectroot.jar
    时,我们将看到打印出来的
    C:\ProjectRoot\dist\ProjectRoot.jar\参考资料\image.png
    。很明显,即使当前工作目录是jar的位置,但是路径不再匹配,添加了jar
    ProjectRoot.jar位置

  • 那么,当我们提取它时,它为什么会起作用呢。当你提取它时,路径是正确的

    C:\ProjectRoot
               dist
                   resources/image.png // from extracted jar
                   ProjectRoot.jar
    
    C:\ProjectRoot\dist>
    运行时,
    资源
    目录是应该在的位置

好了,解释够了。

因此,当您想要读取嵌入式资源时,应该像Andrew Thompson提到的那样,从URL读取它们。此url应与调用它的类或类加载器相关。以下是几种不同的方法:

  • 如前所示

    URL url = getClass().getResource("/resources/image.png");
    
    请注意
    /
    。这将把我们带到类路径的根目录,
    resources
    dir将在这里
    URL
    可以传递给许多构造函数,比如
    ImageIcon(URL)
    或`ImageI.read(URL)

  • 您可以使用:

    InputStream is = getClass().getResourceAsStream("/resources/image.png");
    
    将在引擎盖下使用URL。您还可以对许多构造函数使用
    InputStream

  • 还有一些方法可以使用类加载器,它将从根开始,因此您不需要
    /

    URL url = getClass().getClassLoader().getResource("resources/image.png");
    
  • 因此,有几种方法可以解决这个问题。但一般来说,在使用嵌入式资源时,使用硬编码字符串路径读取
    文件
    从来都不是一个好主意。动态获取路径是可能的,因此您可以使用
    文件
    ,但您仍然需要使用上述技术之一,除非您确实需要
    文件
    ,否则这将是毫无意义的,因为您可以使用
    输入流
    URL


    长话短说 这会管用的

    ProjectRoot
           src\resources\image.png
    
    URL url = getClass().getResource("/resources/image.png");
    Image image = ImageIO.read(url);
    
    “为什么我的Jar不运行,除非我提取文件?”

    这似乎是对您的资源使用
    文件
    的行为。例如

    File file = new File("resources/image.png");
    Image image = ImagIO.read(file);
    
    并且您可以创建项目结构(注意,
    resources
    实际上应该在
    src
    中,这样它就会自动构建到jar中,除非您以不同的方式配置它。但是为了这个参数,假设您在构建到jar中的
    resources
    的位置配置它)

    一些检查:

    • 从IDE运行-工作!为什么?使用
      File
      查找文件系统中的文件。使用相对路径,搜索将从“工作目录”开始,对于IDE,它通常位于项目根目录中。因此,
      “resources/image.png”
      是相对于
      ProjectRoot

    • 构建jar,假设它最终位于项目中的
      dist
      dir中。这就是它看起来的样子

      ProjectRoot
               dist
                  ProjectRoot.jar
      
      现在为了这个参数(实际上是正确的方法),让我们尝试打印资源输入输出程序的URL,这样当您运行jar时,它会打印出文件的URL

      URL url = Test.class.getResource("/resources/image.png");
      System.out.println(url.toString());
      
      当我们运行jar
      C:\ProjectRoot\dist>java-jarprojectroot.jar
      时,我们将看到打印出来的
      C:\ProjectRoot\dist\ProjectRoot.jar\参考资料\image.png
      。很明显,即使当前工作目录是jar的位置,但是路径不再匹配,添加了jar
      ProjectRoot.jar位置

    • 那么,当我们提取它时,它为什么会起作用呢。当你提取它时,路径是正确的

      C:\ProjectRoot
                 dist
                     resources/image.png // from extracted jar
                     ProjectRoot.jar
      
      C:\ProjectRoot\dist>
      运行时,
      资源
      目录是应该在的位置

    好了,解释够了。

    因此,当您想要读取嵌入式资源时,应该像Andrew Thompson提到的那样,从URL读取它们。此url应与调用它的类或类加载器相关。以下是几种不同的方法:

  • 如前所示

    URL url = getClass().getResource("/resources/image.png");
    
    请注意
    /
    。这将把我们带到类路径的根目录,
    resources
    dir将在这里
    URL
    可以传递给许多构造函数,比如
    ImageIcon(URL)
    或`ImageI.read(URL)

  • 您可以使用:

    InputStream is = getClass().getResourceAsStream("/resources/image.png");
    
    将在引擎盖下使用URL。您还可以对许多构造函数使用
    InputStream

  • 还有一些方法可以使用类加载器,它将从根开始,因此您不需要重新加载