2015-04-02 28 views
5

我一直沒有用java處理很長時間,所以我不知道還有什麼要注意的。我希望有人能指出我正確的方向。獲取子包類的資源

目標: 我想使用查找表,作爲文本文件存儲。但是我不想使用絕對路徑,因爲最終我想打包一個版本,並且能夠從任何位置調用它(文本文件將包含在打包版本中)。

當前設置: 我把文本文件,一個名爲「資源」文件夾中(因爲從閱讀Java教程,給我的感覺,這就是我應該把它保持一個更好的結構化項目)。

在根包文件夾中我有一個類(MainClass.java)調用另一個類(LookUpClass.java)在一個子包中。 該文件夾的設置是如下:

  • SRC
    • 的java
      • main.package.com
        • 子包
          • LookUpClass.java
          • PlotterClass.java
        • MainClass.java
    • 資源
      • LookUpTables
        • LookUpTable1.txt
        • LookUpTable2.txt

我在LookUpClass.java中寫了一個方法,它從資源中的查找表中檢索某一行。要檢索文件,並讀出一定行,我用

// Gets respective line from LUT 
private static String getLineFromLUT(int line) { 
    URL url = LookUpClass.class.getClass().getResource("/LookUpTables/LookUpTable1.txt"); 
    File file = new File(url.toURI()); 
    BufferedReader br = new BufferedReader(new FileReader(file)); 

    for (int i = 0; i < line; ++i) 
     br.readLine(); 

    return br.readLine; 
} 

在我的項目結構中的「Java」的文件夾被標記爲「源」,而「資源」被標記爲,那麼,「資源」。

我的測試設置非常簡單:

public static void main(String[] args) throws URISyntaxException, IOException { 
    String c = LookUpClass.getLineFromLUT(5); 
    System.out.println("Color of line 5: " + c); 
} 

輸出:

Color of line 5: 0 0 38 

(這是正確的。)

我加入了完全相同的線路PlotterClass.java和它的工作原理沒關係。

問題:

現在,如果我嘗試同樣在MainClass.java我得到一個錯誤與url被空。似乎無法找到資源/資源文件夾。

我通過各種帖子上SO已經閱讀並嘗試了幾種提出的解決方案,而這一切至今未能:

  • 如果使用LookUpClass.class.getClassLoader().getResource("/LookUpTables/LookUpTable1.txt")都召喚從MainClass.javaLookUpClass.java失敗(url爲空)。
  • 我嘗試使用以下路徑(全部未在任一類的工作): 「LookUpTables/LookUpTable1.txt」(除去起始 「/」) 「/subpackage/LookUpTables/LookUpTable1.txt」 」 ../子包/ LookUpTables/LookUpTable1.txt「
  • 由於使用Idea IntelliJ,我選中了」設置>構建,執行,部署> Compiter>資源模式「,並在模式中添加了」* .txt「。沒有改變。
  • 如果添加Class c = LookUpClass.class.getClass();,則在調試模式下,c是「class.java.lang.Class」。我期待像「main.package.com.subpackage.LookUpClass」。
  • 在某些時候,我嘗試使用getResourceAsStream(),但我不明白如何得到我的(例如)第5行,所以我放棄了它。如果能解決我的問題,我願意在此閱讀。

我不知道如何解決這個問題。我意識到在這一點上,我只是在嘗試一些事情,甚至不理解爲什麼它可以或不可以工作。 對我來說,它似乎是LookUpClass.javaMainClass.java不同的位置運行。但「資源」 - 文件夾和各自的文本文件位置永遠不會改變。如何在一個案件中找到該文件,但在另一個案件中找不到該文件?

+0

還有三個問題:您是否在使用IDE(如Eclipse)?你是否使用任何構建工具(如Maven)?您的文本文件意味着是由用戶更新還是他們是發行版的一部分? – Seelenvirtuose 2015-04-02 13:22:53

+0

您可以嘗試確保您正在使用的類對象是否實際加載,例如,通過'try {0}來嘗試加載該類對象。 \t \t \t \t}趕上(最終ClassNotFoundException的前){ \t \t \t \t}' – muued 2015-04-02 13:38:39

+0

@Seelenvirtuose是這兩個:我使用的IntelliJ和項目確實是使用Maven構建。文本文件意味着是靜態的並且是分發的一部分。它們包含熱圖的RGB代碼。 – fukiburi 2015-04-02 13:47:19

回答

1

Maven有一個standard directory layout 。目錄src/main/resources適用於此類應用程序資源。將您的文本文件放入其中。

現在基本上有兩種選擇中準確地放置您的文件:

  1. 資源文件屬於一類。

這是一個代表GUI元素(面板)的類,它需要同時顯示一些圖像。

在這種情況下,將資源文件放入與相應類相同的目錄(包)中。例如。名爲your.pkg.YourClass地方的資源文件到該目錄your/pkg類:

src/main 
+-- java/ 
| +-- your/pkg/ 
| | +-- YourClass.java 
+-- resources/ 
     +-- your/pkg/ 
      +-- resource-file.txt 

現在通過加載相應的類資源。 your.pkg.YourClass你有下面的代碼片段加載的類中:

String resource = "resource-file.txt"; // the "file name" without any package or directory 
Class<?> clazz = this.getClass(); // or YourClass.class 
URL resourceUrl = clazz.getResource(resource); 
if (resourceUrl != null) { 
    try (InputStream input = resourceUrl.openStream()) { 
     // load the resource here from the input stream 
    } 
} 

注意:您也可以加載通過類的類加載器的資源:

String resource = "your/pkg/resource-file.txt"; 
ClassLoader loader = this.getClass().getClassLoader(); // or YourClass.class.getClassLoader() 
URL resourceUrl = loader.getResource(resource); 
if (resourceUrl != null) { 
    try (InputStream input = resourceUrl.openStream()) { 
     // load the resource here from the input stream 
    } 
} 

選擇,你會發現更方便的東西。

  1. 該資源屬於整個應用程序。

在這種情況下,只需將資源直接放置到src/main/resources目錄或適當的子目錄中即可。讓我們來看一個例子您的查找文件:

src/main/resources/ 
    +-- LookupTables/ 
     +-- LookUpTable1.txt 

然後,您都必須用當前線程的上下文類加載器或應用程序類加載器(無論是比較合適的通過類加載器加載資源, - 去搜索關於這個問題的文章如果感興趣的話)。我會告訴你兩種方法:

String resource = "LookupTables/LookUpTable1.txt"; 
ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader(); 
ClassLoader sysLoader = ClassLoader.getSystemClassLoader(); 
URL resourceUrl = ctxLoader.getResource(resource); // or sysLoader.getResource(resource) 
if (resourceUrl != null) { 
    try (InputStream input = resourceUrl.openStream()) { 
     // load the resource here from the input stream 
    } 
} 

作爲第一個建議,使用當前線程的上下文類加載器。在獨立的應用程序中,這將是系統類加載器或將系統類加載器作爲父類。 (這些類加載器之間的區別對於也加載資源的庫來說將變得重要)。

您應該總是使用類加載器來加載資源。通過這種方式,您可以使加載與該位置無關(只需注意啓動應用程序時文件位於類路徑中),並且可以將整個應用程序打包到仍然可以找到資源的JAR文件中。

+0

非常感謝您抽出時間解釋一切,並舉例說明!我終於可以在線程的裝載器和系統類加載器中使用它。我還沒有嘗試你的第一個解決方案,但我打算在下一步做,因爲查找表實際上只屬於/被這個類使用。 (對不起,因爲復活節假期,延長了週末) – fukiburi 2015-04-07 08:48:35

+0

奇怪的是,當嘗試方法1時,如果我實際添加完整文件夾路徑(即'String resource =「your/pkg/resource-file.txt「),但它不起作用,如果我只是單獨使用文件名('String resource =」resource-file.txt「')。我錯過了什麼? – fukiburi 2015-04-07 09:21:12

+0

@fukiburi不,你沒有錯過任何東西。我做到了!我混淆了'ClassLoader.getResource'和'Class.getResource'。使用類加載器時,還必須指定(類路徑相對)路徑。我會相應地編輯我的答案。 – Seelenvirtuose 2015-04-07 10:44:47

0

我試圖重現您提供給您的MWE的問題,但沒有成功。我上傳了我的項目,包括一個pom.xml(你提到你使用Maven的)位置:http://www.filedropper.com/stackoverflow 這是我的查詢類是什麼樣子(也展示瞭如何使用的getResourceAsStream方法):

public class LookUpClass { 

    final static String tableName = "resources/LookUpTables/LookUpTable1.txt"; 

    public static String getLineFromLUT(final int line) { 
     final URL url = LookUpClass.class.getResource(tableName); 
     if (url.toString().startsWith("jar:")) { 
      try (final URLClassLoader loader = URLClassLoader 
        .newInstance(new URL[] { url })) { 
       return getLineFromLUT(
         new InputStreamReader(
           loader.getResourceAsStream(tableName)), line); 
      } catch (final IOException e) { 
       e.printStackTrace(); 
      } 
     } else { 
      return getLineFromLUT(
        new InputStreamReader(
          LookUpClass.class.getResourceAsStream(tableName)), 
        line); 
     } 
     return null; 
    } 

    public static String getLineFromLUT(final Reader reader, final int line) { 
     try (final BufferedReader br = new BufferedReader(reader)) { 
      for (int i = 0; i < line; ++i) 
       br.readLine(); 
      return br.readLine(); 
     } catch (final IOException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 
} 
+0

感謝您花時間幫助我解決問題!特別是如何使用getResourceAsStream()並讀取一行的部分非常有用。 – fukiburi 2015-04-07 09:02:21