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

Eli*_*mal 0 java swing export jar image

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

Pau*_*tha 5

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

这似乎是使用File您的资源的行为.举个例子

File file = new File("resources/image.png");
Image image = ImagIO.read(file);
Run Code Online (Sandbox Code Playgroud)

而你的项目结构(请注意,它resources实际上应该在其中src,因此它会自动构建到jar中 - 除非你以不同的方式配置它.但是为了这个参数,让我们说你确实把它resources构建到jar的内部)

C:\
   Project
        resources\image.png
Run Code Online (Sandbox Code Playgroud)

一些考试:

  • 从IDE运行 - 工作!为什么?使用File查找文件系统上的文件.使用相对路径,搜索将从"工作目录"开始,在IDE的情况下,通常是项目根目录.所以"resources/image.png"是一个有效的路径,相对于ProjectRoot

  • 建立jar,说它最终dist在项目的目录中.这就是它的样子

    ProjectRoot
             dist
                ProjectRoot.jar
    
    Run Code Online (Sandbox Code Playgroud)

    现在为了这个参数(并且实际上是正确的方法),让我们尝试在out程序中打印资源的URL,这样当你运行jar时,它会打印出文件的URL

    URL url = Test.class.getResource("/resources/image.png");
    System.out.println(url.toString());
    
    Run Code Online (Sandbox Code Playgroud)

    当我们运行jar时C:\ProjectRoot\dist> java -jar ProjectRoot.jar我们将看到打印输出C:\ProjectRoot\dist\ProjectRoot.jar!\resources\image.png.即使当前工作目录是jar的位置,路径也不再匹配,你可以看到添加的jar ProjectRoot.jar!位置.

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

    C:\ProjectRoot
               dist
                   resources/image.png // from extracted jar
                   ProjectRoot.jar
    
    Run Code Online (Sandbox Code Playgroud)

    从你跑的时候C:\ProjectRoot\dist >,resourcedir应该在哪里.

好了解释.

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

  1. 如图所示

    URL url = getClass().getResource("/resources/image.png");
    
    Run Code Online (Sandbox Code Playgroud)

    请注意/.这将把我们带到类路径的根,resourcesdir将在哪里.URL可以传递给许多构造函数,比如ImageIcon(URL)或者`ImageI.read(URL)

  2. 您可以使用:

    InputStream is = getClass().getResourceAsStream("/resources/image.png");
    
    Run Code Online (Sandbox Code Playgroud)

    哪个将使用引擎盖下的URL.您也可以使用InputStream许多构造函数.

  3. 还有一些方法可以使用类加载器,它将从根开始,所以你不需要 /

    URL url = getClass().getClassLoader().getResource("resources/image.png");
    
    Run Code Online (Sandbox Code Playgroud)

所以有几种方法可以解决它.但一般来说,File使用嵌入式资源时,使用硬编码字符串路径进行读取绝不是一个好主意.可以动态获取路径以便你可以使用File,但你仍然需要使用上述技术之一,除非你真的需要一个File没有意义的东西,因为你可以用InputStream或者做你需要的东西.URL


使长话短说

这会奏效

ProjectRoot
       src\resources\image.png

URL url = getClass().getResource("/resources/image.png");
Image image = ImageIO.read(url);
Run Code Online (Sandbox Code Playgroud)