簡體   English   中英

Java在靜態方法中讀取文件,使用ClassLoader給出FileNotFoundException

[英]Java read file within static method, using ClassLoader gives FileNotFoundException

我想在我的java類中讀取一個文件。 我的問題類似於這個 ,但有兩個不同之處。 首先,我使用不同的項目布局:

/ src目錄/ COM /公司/項目
/資源

在資源文件夾中,我有一個名為“test.txt”的文件:

/resources/test.txt

在項目文件夾中,我有一個類test.java

/src/com/company/project/test.java

我希望mu java類能夠在STATIC METHOD中讀取test.txt的內容。 我嘗試過以下方法:

private static String parseFile()
{
    try
    {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        String fileURL = classLoader.getResource("test.txt").getFile();

        File file = new File(fileURL);


        ...
    }   
}

以及以下路徑:

File file1 = new File("test.txt");
File file2 = new File("/test.txt");
File file3 = new File("/resources/test.txt");

但是當我想要讀取文件時,它們都會拋出FileNotFoundException。 如何根據我的項目設置以及該方法需要靜態的事實在上面的代碼段中正確聲明我的文件的路徑?

經過無休止的試驗,我放棄了任何類型的ClassLoader和getResource方法。 絕對沒有任何效果,特別是如果開放嘗試來自另一個項目。 我總是得到bin文件夾而不是src文件夾。 所以我設計了以下工作:

public class IOAccessory {

    public static String getProjectDir() {
        try {
            Class<?> callingClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
            URL url = callingClass.getProtectionDomain().getCodeSource().getLocation();
            URI parentDir = url.toURI().resolve("..");          
            return parentDir.getPath();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return "";
    }
}

getProjectDir方法返回調用它的項目的物理路徑,例如C:/ workspace / MyProject /。 之后,您需要做的就是連接資源文件的MyProject中的相對路徑以打開流:

public void openResource() throws IOException {
    InputStream stream = null;
    String projectDir = IOAccessory.getProjectDir();
    String filePath = "resources/test.txt";
    try {
        stream = new FileInputStream(projectDir + filePath);
        open(stream);
    } catch(Exception e) {
        e.printStackTrace();
    } finally {
        if (stream != null)
            stream.close();
    }
}

無論openResource方法是靜態還是非靜態方法,以及是從項目內還是從構建路徑上的其他項目調用,該方法都有效。

您應該使用與資源相同的JAR中的類的類加載器而不是TCCL。 然后,您需要使用完整路徑指定資源的名稱。 通常不喜歡將它們作為文件訪問。 只需直接打開它進行讀取(如果需要,可將其復制到臨時文件中):

InputStream is =
  Project.class.getClassLoader().getResourceAsStream("/resource/test.txt");

順便說一句:如果您只是想打開一個文件,則需要使用相對文件名。 這是相對於start dir搜索的,它通常是項目主目錄(在eclipse中):

File resource = new File("resource/test.txt");

(但如果你將它打包成JAR,這將不起作用)。

這實際上取決於IDE如何從項目中生成輸出。 通常,類加載器相對於調用類加載資源,但如果處理正確,“資源”將最終位於輸出文件夾層次結構的“根”中,您可以相應地訪問它們。

例如,如果我在IntelliJ IDEA中重新創建代碼,則在名為com/acme/TestClass.class ,在構建時會在IDE中生成以下輸出結構。 這假設我將“test.txt”放在我稱為“資源”的文件夾中,並將該文件夾指定為“資源根”:

/com
  /acme
    TestClass.class
test.txt

文本文件最終位於輸出文件夾的根目錄中,因此訪問它很簡單。 當我嘗試在TestClass中的靜態方法中加載文件時,以下代碼適用於我:

ClassLoader cl = TestClass.class.getClassLoader();
InputStream is = cl.getResourceAsStream("test.txt");

其他答案中未涉及的唯一內容是您的URL轉換為文件可能無法正常工作。 如果項目上方的目錄包含必須解碼的字符,那么調用'getResource(“test.txt”)。getFile()'不會給你一個有效的java.io.File路徑。

我從靜態函數加載了用於openGL ES的着色器。

請記住,您必須使用小寫字母作為文件和目錄名稱,否則操作將失敗

public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...

    public static int loadShader() {
        //    Read file as input stream
        InputStream inputStream = MyGLRenderer.class.getResourceAsStream("/res/raw/vertex_shader.txt");

        //    Convert input stream to string
        Scanner s = new Scanner(inputStream).useDelimiter("\\A");
        String shaderCode = s.hasNext() ? s.next() : "";
    }

    ...

}

另一種將輸入流轉換為字符串的方法。

byte[] bytes;
String shaderCode = "";
try {
    bytes = new byte[inputStream.available()];
    inputStream.read(bytes);
    shaderCode = new String(bytes);
}
catch (IOException e) {
    e.printStackTrace();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM