2013-05-15 300 views
90

我从我的Java项目的已编译JAR中的包中加载文本文件。相关的目录结构如下:正在使用getResourceAsStream返回null

/src/initialization/Lifepaths.txt 

的代码加载该文件是:

public class Lifepaths { 
    public static void execute() { 
     System.out.println(Lifepaths.class.getClass(). 
      getResourceAsStream("/initialization/Lifepaths.txt")); 
    } 

    private Lifepaths() {} 

    //This is temporary; will eventually be called from outside 
    public static void main(String[] args) {execute();} 
} 

打印出来总是会打印null,不管我用什么。我不知道为什么上面是行不通的,所以我也试着:

  • "/src/initialization/Lifepaths.txt"
  • "initialization/Lifepaths.txt"
  • "Lifepaths.txt"

无论这些工作。 I'vereadnumerousquestions到目前为止的话题,但他们都没有帮助 - 通常,他们只是说使用根路径加载文件,我已经在做。那个,或者只是从当前目录加载文件(只是加载filename),我也试过了。正在使用适当的名称将文件编译到适当位置的JAR中。

我该如何解决这个问题?

+3

你是否检查过它真的*是*在jar文件中?你有没有检查文件夹? –

+0

@JonSkeet它确实被编译到适当位置的JAR文件中,并且情况正确。 – Zyerah

+0

@greedybuddha虽然我无法从静态上下文中调用它,但我可以使用'Lifepaths.class'调用它。这就是说,为什么'getClassLoader()'允许它工作? (另外,请随时发布答案!) – Zyerah

回答

93

Lifepaths.class.getClass().getResourceAsStream(...)使用系统类加载器加载资源,它显然失败,因为它看不到您的JAR

Lifepaths.class.getResourceAsStream(...)使用加载Lif的同一类加载器加载资源epaths类,它应该有权访问您的JAR中的资源

+42

只需添加,当调用getResourceAsStream(name)时,名称必须以“/”开头。我不确定这是否有必要,但没有它我有问题。 – David

+3

从昨天早上8点开始,我一直在这样做。救了我。我也需要一个主要的斜线来使它工作。 – kyle

+0

我一直在尝试2天,直接找到解决方案,我的问题,最后在这里。谢谢。 –

40

的规则如下:

  1. 检查要在JAR内部装载(从而也确保它实际添加到JAR)
  2. 使用绝对路径的文件的位置:路径始于JAR
  3. 使用相对路径的根目录:路径在你打电话的getResource/getResoucreAsStream

,并尝试类的包目录开始:

Lifepaths.class.getResourceAsStream("/initialization/Lifepaths.txt") 

代替

Lifepaths.class.getClass().getResourceAsStream("/initialization/Lifepaths.txt") 

(不知道这是否有差别,但前者将使用正确的ClassLoader/JAR,虽然我不知道后者)

+1

我已经完成了所有这三件事。请重新阅读我的问题。 – Zyerah

+0

从你的问题中不清楚什么是“相关的目录结构”,如果你真的检查过JAR中文件的位置和位置(步骤1) – Puce

+0

你关于相对路径的评论终于解决了我的问题;谢谢! –

26

因此,有几种方法可以从jar中获取资源,并且每种语法的路径需要以不同方式指定时略有不同。

我看到的最好的解释是这篇文章从JavaWorld。我会在这里总结,但如果你想知道更多,你应该看看这篇文章。

方法

1)ClassLoader.getResourceAsStream()

格式:“/” - 分隔的名称;没有领先的“/”(所有名称都是绝对的)。

实施例:this.getClass().getClassLoader().getResourceAsStream("some/pkg/resource.properties");

2)Class.getResourceAsStream()

格式: “/” - 分隔的名称;前导“/”表示绝对名称;所有其他名称是相对于类的包

例子:this.getClass().getResourceAsStream("/some/pkg/resource.properties");

+0

您的第二个示例已损坏 –

+1

第二个示例没有中断,正如我在答案中所述,它取决于资源的位置。 – greedybuddha

-12

@Emracool ......我建议你的选择。由于您似乎正在尝试加载* .txt文件。更好使用FileInputStream()而不是这个恼人的getClass().getClassLoader().getResourceAsStream()getClass().getResourceAsStream()。至少你的代码会正确执行。

+0

什么? -1为这样的工作答案。无论。但上面提出的解决方案肯定会起作用。 – Jain

+0

@mu ....你有什么编辑? – Jain

+0

重新格式化了代码块。 –

12

不要使用绝对路径,使它们相对于项目中的'资源'目录。快速和脏的代码,显示目录'资源'中MyTest.txt的内容。

@Test 
public void testDefaultResource() { 
    // can we see default resources 
    BufferedInputStream result = (BufferedInputStream) 
     Config.class.getClassLoader().getResourceAsStream("MyTest.txt"); 
    byte [] b = new byte[256]; 
    int val = 0; 
    String txt = null; 
    do { 
     try { 
      val = result.read(b); 
      if (val > 0) { 
       txt += new String(b, 0, val); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } while (val > -1); 
    System.out.println(txt); 
} 
2

不知道是否有帮助,但在我的情况下,我有我的资源在/ src /文件夹,并得到此错误。 然后,我将图片移至bin文件夹,并解决了问题。

2

确保您的资源目录(例如“src”)在您的类路径中(确保它是eclipse中构建路径中的源目录)。

确保clazz从主类加载器加载。

然后,加载的src /初始化/ Lifepaths.txt,使用

clazz.getResourceAsStream("/initialization/Lifepaths.txt"); 

为什么: clazz.getResourcesAsStream(foo)查找富从clazz中的类路径相对于目录clazz中住在内。前导“/”使它从clazz类路径中任何目录的根目录加载。

除非你在像Tomcat这样的容器中,或者直接使用ClassLoaders进行操作,否则你可以将你的eclipse /命令行类路径作为唯一的类加载器类路径。

6

似乎存在与您正在使用的ClassLoader问题。使用contextClassLoader加载类。这与是否处于静态/非静态方法无关

Thread.currentThread().getContextClassLoader().getResourceAsStream ......

-1

什么工作对我来说是添加在我的项目/ Java的资源/ src中的文件,然后使用

this.getClass().getClassLoader().getResourceAsStream(myfile.txt); 

我并不需要明确地将此文件的路径添加到(添加到/ SRC这是显然)

+0

错误的java语法 –

1

我发现自己在类似的问题。由于我使用maven我需要更新我的pom.xml包括这样的事情:

... 
</dependencies> 
<build> 
    <resources> 
     <resource> 
      <directory>/src/main/resources</directory> 
     </resource> 
     <resource> 
      <directory>../src/main/resources</directory> 
     </resource> 
    </resources> 
    <pluginManagement> 
     ... 

注意在那里的资源标记,指定该文件夹。如果您有嵌套项目(就像我一样),那么您可能想从其他区域获取资源,而不是仅在您正在使用的模块中。这有助于减少在每个回购中保留相同的文件(如果使用类似的配置数据)

相关问题