2013-05-15 301 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> 
     ... 

注意在那裏的資源標記,指定該文件夾。如果您有嵌套項目(就像我一樣),那麼您可能想從其他區域獲取資源,而不是僅在您正在使用的模塊中。這有助於減少在每個回購中保留相同的文件(如果使用類似的配置數據)

相關問題