Java在静态方法中读取文件,使用ClassLoader给出FileNotFoundException

问题描述 投票:3回答:5

我想在我的java类中读取一个文件。我的问题类似于to this one,但有两个不同之处。首先,我使用不同的项目布局:

/ src目录/ COM /公司/项目 /资源

在资源文件夹中,我有一个名为“test.txt”的文件:

/resources/test.txt

在项目文件夹中,我有一个类test.java

/双人床/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。如何根据我的项目设置以及该方法需要静态的事实在上面的代码段中正确声明我的文件的路径?

java file classloader
5个回答
4
投票

经过无休止的试验,我放弃了任何类型的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:/工作区/ 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方法是静态还是非静态方法,以及是从项目内还是从构建路径上的其他项目调用,该方法都有效。


2
投票

您应该使用与资源相同的JAR中的类的类加载器而不是TCCL。然后,您需要使用完整路径指定资源的名称。通常不喜欢将它们作为文件访问。只需直接打开它进行读取(如果需要,可将其复制到临时文件中):

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

顺便说一句:如果您只是想打开一个文件,则需要使用相对文件名。这是相对于start dir搜索的,它通常是项目主目录(在eclipse中):

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

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


0
投票

这实际上取决于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");

0
投票

其他答案中没有涉及的唯一内容是你的URL conversion to file可能无法正常工作。如果项目上方的目录包含必须解码的字符,则调用'getResource(“test.txt”)。getFile()'并不会为您提供有效的java.io.File路径。


0
投票

我从静态函数加载了用于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();
}
© www.soinside.com 2019 - 2024. All rights reserved.