加载字体文件时的Eclipse Java文件FileInputStream与输入流[重复]
Posted
技术标签:
【中文标题】加载字体文件时的Eclipse Java文件FileInputStream与输入流[重复]【英文标题】:Eclipse Java File FileInputStream vs Input Stream when loading font file [duplicate] 【发布时间】:2014-07-14 06:47:51 【问题描述】:我正在阅读一些教程,但在将字体文件加载到 Eclipse Java 项目时遇到问题。我在 SO 上尝试了许多建议的解决方案,最终找到了一个(使用 FileInputStream)对我有用,但在项目导出为可运行 JAR 时却没有。另一方面,在我加载图标的另一个项目中使用相同的目录结构,所以我猜问题不在于路径本身。
这里是目录结构:
代码如下:
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();
所以,困扰我的是:
- 为什么这不起作用(似乎找不到字体文件),因为它抛出 NullPointerException
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");
【问题讨论】:
@Darkhogg 您指向的帖子不是对我帖子的完整回答,只是(可能)对 JAR 部分的回答。如果您阅读我的帖子,您会发现我在实施他们建议的解决方案时遇到问题 - 即使用 getResourceAsStream(),这就是我问这个问题的原因。 【参考方案1】:虽然@peeskillet 提供了非常简洁的答案,但如果有人想进一步阅读,也可以在这里找到很好的解释:
Loading Java Files
我之所以提到这一点,是因为对于使用不同方法在 Java 中加载文件的正确方法似乎存在很多问题和困惑(包括我自己的问题)。
所以最后两种方法都有效:
// This works both within Eclipse project and in runnable JAR
InputStream fis = this.getClass().getResourceAsStream("/examples/resources/verdana.ttf");
或
// This works both within Eclipse project and in runnable JAR
InputStream fis = this.getClass().getClassLoader().getResourceAsStream("examples/resources/verdana.ttf");
【讨论】:
【参考方案2】:回答你关于斜线的最后一个问题:当你使用getClass()
时,搜索将从调用类开始。如果您不使用第一个类,该文件将在不存在的examples/examples/resource
中查找(因为调用类在examples
中)。正斜杠的作用是将搜索带到类路径根目录。
这在 Eclipse 项目中有效,但在导出到可运行 JAR 时无效, 此外,许多人建议
InputStream
应优先于FileInputStream
如果您的应用程序需要某个资源并且将其打包在 jar 中,则应该从 URL 中读取,通过 getClass().getResource()
返回资源的实际 URL,或 @ 987654327@ 以InputStream
的形式将资源作为流返回,从URL 中获取。你也可以getClassLoader()
,但这里是主要区别
getClass()
- 如上所述,搜索将从调用类的位置开始。所以无论类在什么包中,这就是搜索开始的地方。像这样的结构
ProjectRoot
src
com
example
MyClass.class
resources
resource.ttf
将导致搜索从包的example
目录内部开始。因此,如果您尝试使用此路径 resources/resource.ttf
if 将失败,因为examples
目录中没有resources
目录。使用/
会将搜索带到类路径的根目录,即src
(至少从IDE 的角度来看——它将被压缩到classes
)。所以/resources/resource.ttf
可以工作,因为src/resources/resource.ttf
存在。
getClassLoader()
- 从类路径根目录开始搜索,所以是src
。你不需要额外的/
,因为resources/resource.ttf
就像说它作为src/resources/resource.ttf
存在。
另一方面,当您使用任何形式的File
搜索时,搜索将根据本地文件系统进行。至于您的问题,为什么在您的 IDE 上使用 File
是因为 IDE 不是从 jar 启动程序,而是从 IDE 本身启动程序,并使用当前工作目录作为根路径。
所以要记住的主要事情是,当您的文件是应用程序资源时,请从类路径中读取它。
InputStream is = getClass().getResourcAsStream("/path/to/file");
关于 IDE 功能的进一步说明。你的是日食。如果你在你的文件系统中去你的项目,你会看到一个bin
文件,就你的IDE而言是类路径。编译代码时,资源会被复制到该路径中。这就是当您尝试读取文件时 IDE 将搜索的位置,因为项目是工作目录,并且使用非绝对路径,这就是搜索发生的位置
【讨论】:
谢谢你,我给了+1,如果没有人提供更简洁的答案,我会接受你的答案作为最终答案。但我怀疑有人会匹配这个答案。 只要你从我的解释中完全理解,这就是最重要的:-) 好的,这似乎是这种情况下的通用解决方案,因为它似乎在 IDE 和可运行的 JAR 中都可以工作,你同意吗? InputStream fis = this.getClass().getClassLoader().getResourceAsStream("examples/resources/verdana.ttf"); 一般来说应该可以。请参阅我更新的答案的最后一部分。也许您会对 Eclipse 及其工作原理有更好的了解 :-)以上是关于加载字体文件时的Eclipse Java文件FileInputStream与输入流[重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何打开用eclipse没有.project文件的Java工程
eclipse里面 左边项目里面文件夹显示的字体怎么改。我知道是在windows-preferences-general-apperance里