java - 加载字体文件时Eclipse Java File FileInputStream vs Input Stream

标签 java eclipse jar inputstream fileinputstream

<分区>

我正在阅读一些教程,但在将字体文件加载到 Eclipse Java 项目时遇到了问题。我在 SO 上尝试了这里建议的许多解决方案,并最终找到了一个对我有用的解决方案(使用 FileInputStream),但当项目导出为可运行的 JAR 时却没有。另一方面,在我加载图标的另一个项目中使用相同的目录结构,所以我猜问题不在路径本身。

这是目录结构enter image description here :

代码如下:

package examples;

import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Test01 extends JPanel {

    String text = "Free the bound periodicals";
    Font fon;
    FileInputStream fis;
    // InputStream fis;

    @Override
    public void paintComponent(Graphics comp) {
        Graphics2D comp2D = (Graphics2D) comp;


        // This (for another project) works both in Eclipse and in runnable  JAR
        // ImageIcon loadIcon = new ImageIcon(getClass().getResource("/examples/resources/load.gif"));

        // This (quite contrary to many SO suggestions) doesn't work in Eclipse for this project, why?
        // fis = this.getClass().getResourceAsStream("/examples/resources/vedrana.ttf");

        // This (quite contrary to many SO suggestions) doesn't work in Eclipse for this project, why?
        // fis = this.getClass().getClassLoader().getResourceAsStream("/examples/resources/verdana.ttf");

        // This works within Eclipse project but not when exported to runnable JAR, 
        // Moreover many suggest that InputStream should be favored over FileInputStream
        try {
            fis = new FileInputStream(new File(getClass().getResource("/examples/resources/verdana.ttf").toURI()));
        } catch (FileNotFoundException e1) {
            JOptionPane.showMessageDialog(this, "FileNotFoundException!");
        } catch (URISyntaxException e1) {
            JOptionPane.showMessageDialog(this, "URISyntaxException!");
        } catch (Exception e1) {
            JOptionPane.showMessageDialog(this, "NullPointerException!");
        }

        try {
            fon = Font.createFont(Font.TRUETYPE_FONT, fis);
        } catch (FontFormatException e) {
            // TODO Auto-generated catch block
            System.out.println("Error - FontFormatException " + e.getMessage());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.out.println("Error - IOException " + e.getMessage());
        }

        fon = fon.deriveFont(Font.PLAIN, 72);

        FontMetrics metrics = getFontMetrics(fon);
        comp2D.setFont(fon);
        comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        int x = (getSize().width - metrics.stringWidth(text)) / 2;
        int y = getSize().height / 2;

        comp2D.drawString(text, x, y);
    }

    public static void main(String[] args) {
        JFrame mainFrame = new JFrame("Main Menu");
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setSize(1000, 250);
        mainFrame.setVisible(true);
        mainFrame.add(new Test01());
        // mainFrame.pack();
    }
}

所以,困扰我的是:

- 为什么这不起作用(似乎找不到字体文件),因为它抛出 空指针异常

fis = this.getClass().getResourceAsStream("/examples/resources/vedrana.ttf");

这也行不通

fis = this.getClass().getClassLoader().getResourceAsStream("/examples/resources/verdana.ttf");

- 为什么这在 Eclipse 项目中有效,但在导出到 可运行的 JAR

fis = new FileInputStream(new File(getClass().getResource("/examples/resources/verdana.ttf").toURI()));

更新 事实证明这会起作用:

fis = this.getClass().getClassLoader().getResourceAsStream("examples/resources/verdana.ttf");

问题出在第一个斜杠 - 路径应该是“examples/resources/verdana.ttf”而不是“/examples/resources/verdana.ttf”。它适用于 Eclipse 和可运行的 JAR。

现在,让我感兴趣的是为什么在这种情况下第一个斜线是必要的

ImageIcon loadIcon = new ImageIcon(getClass().getResource("/examples/resources/load.gif"));

更新 2: 在沮丧为什么这个方法不起作用之后

InputStream fis = this.getClass().getResourceAsStream("/examples/resources/verdana.ttf");

我从 Eclipse 中删除了整个类,现在这两种方法都可以在 Eclipse 和 runanble JAR 中运行——就像它应该的那样。

InputStream fis = this.getClass().getResourceAsStream("/examples/resources/verdana.ttf");

InputStream fis = this.getClass().getClassLoader().getResourceAsStream("examples/resources/verdana.ttf");

最佳答案

要回答您对斜杠的最后一个担忧:当您使用 getClass() 时,搜索将从调用类开始。如果您不使用第一个类,将在不存在的 examples/examples/resource 中查找文件(因为调用类在 examples 中)。正斜杠的作用是将搜索带到类路径根目录。

This works within Eclipse project but not when exported to runnable JAR, Moreover many suggest that InputStream should be favored over FileInputStream

如果您的应用程序需要资源并将其打包在 jar 中,则应该通过 getClass().getResource() 从 URL 中读取返回资源的实际 URL,或 getClass().getResourceAsStream()InputStream 的形式返回资源作为从 URL 获得的流。您也可以 getClassLoader(),但这里是主要区别

  • getClass() - 如上所述,搜索将从调用类的位置开始。因此,无论类在哪个包中,搜索都是从那里开始的。像这样的结构

    ProjectRoot
              src
                 com
                    example
                         MyClass.class
                 resources
                        resource.ttf
    

    将导致搜索从包的 example 目录开始。因此,如果您尝试使用此路径 resources/resource.ttf 会失败,因为 examples 中没有 resources 目录 目录。使用 / 会将搜索带到类路径的根目录,即 src(至少从 IDE 的角度来看 - 它将被压缩到 )。所以 /resources/resource.ttf 可以工作,因为 src/resources/resource.ttf 存在。

  • getClassLoader() - 从类路径根开始搜索,因此 src。您不需要额外的 / 因为 resources/resource.ttf 就像是说它作为 src/resources/resource.ttf 存在。


另一方面,当您使用任何形式的文件 搜索时,搜索将根据本地文件系统进行。至于您的问题,为什么使用 File 可以在您的 IDE 上运行,是因为 IDE 不是从 jar 启动程序,而是从 IDE 本身启动程序,并使用当前工作目录作为根路径。

所以要记住的主要事情是,当您的文件是应用程序资源时,请从类路径中读取它。

InputStream is = getClass().getResourcAsStream("/path/to/file");

关于您的 IDE 功能的进一步说明。你的是 eclipse 。如果你去你的文件系统中的项目,你会看到一个 bin 文件,就你的 IDE 而言是类路径。当您编译代码时,资源会被复制到该路径中。这就是当您尝试读取文件时 IDE 将搜索的位置,因为项目是工作目录,并且使用非绝对路径,这就是搜索发生的位置

关于java - 加载字体文件时Eclipse Java File FileInputStream vs Input Stream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23854130/

相关文章:

Eclipse IDE : Add/change default filetypes?

android - 从android gradle插件生成eclipse项目

java - Gradle IntelliJ创意

gwt - 需要帮助将 GWT 库模块打包到 JAR 中

java - :graphicimage not working in c:foreach

java - 使用 SnakeYaml 转储带引号的值

java - Hamcrest containsInAnyOrder 如果字符串包含则匹配

java - spring框架3.2.13是否与Java 11兼容

iOS-Web服务: Webservice for iOS client

java - JAR中有多个可运行类,如何运行它们?