本文介绍了加载字体文件时的Eclipse Java File FileInputStream vs Input Stream的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am going through some tutorials and I have a problem with loading font file into Eclipse Java Project. I tried many solutions suggested here on SO, and eventually find one (using FileInputStream) which does work for me, but not when the project is exported as runnable JAR. On the other hand using same directory structure in the other project where I load icons works, so I guess the problem is not in the path itself.

这里是目录结构:

代码如下:

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.

The problem was in first slash - path should be "examples/resources/verdana.ttf" instead of "/examples/resources/verdana.ttf". It works both in Eclipse and in runnable JAR.

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

Now, what intrigues me is why is then that first slash necessary in this case

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

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

UPDATE 2:After being frustrated why this method doesn't work

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

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

I deleted whole class from Eclipse and now BOTH methods work within Eclipse and runanble JAR - just as it should be.

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

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

推荐答案

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

To answer your last concern about the slash: when you use getClass() the search will begin from the calling class. If you don't use the first class the file will be looked for in examples/examples/resource (since the calling class is in examples) which doesn't exist. What the forward slash does is bring the search to the class path root.

这在 Eclipse 项目中有效,但在导出到可运行的 JAR 时无效,此外,许多人建议 InputStream 应该优于 FileInputStream

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

If you a resource is needed for you application and is packaged in the jar, it should be read from an URL, either via getClass().getResource() which returns an actual URL to a resource, or getClass().getResourceAsStream() which return the resource as a stream in the form of InputStream, obtained from the URL. You can also getClassLoader(), but here are the main differences

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

  • getClass() - As stated above, the search will begin from the location of the calling class. So whatever package the class is in, that's where the search begins. A structure like this

ProjectRoot
          src
             com
                example
                     MyClass.class
             resources
                    resource.ttf

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

will cause the the search to begin from inside example dir of the package. So if you try and use this path resources/resource.ttf if will fail, because there is no resources dir in the examples dir. Using the / will bring the search to the root of the class path, which is the src (at least from IDE perspective - which will get jar'ed into a classes). So /resources/resource.ttf would work, as src/resources/resource.ttf exists.

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

getClassLoader() - begins it's search from the class path root, so the src. You don't need the extra / because resources/resource.ttf is like saying it exists as src/resources/resource.ttf.

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

On another note, when you use any form of a File search, the search will be in terms of the local file system. So as to your question why using File would work on your IDE, is because the IDE launches the program not from the jar, but from the IDE itself and uses the current working directory as the root path.

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

So the main thing to keep in mind is that when your file is an application resources, read it as such from the class path.

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

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


Further explanation about the functionality of your IDE. Yours is eclipse. If you go to you project in yout file system, you will see a bin file, in terms of your IDE is the class path. When you compile your code, the resources get copied into that path. That's where the IDE will search when you try and read as a file, as the project is the working directory, and using a non absolute path, that's where the searching happens

这篇关于加载字体文件时的Eclipse Java File FileInputStream vs Input Stream的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 03:04