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

Java读取静态方法中的文件,使用ClassLoader给出FileNotFoundException,java,file,classloader,Java,File,Classloader,我想在java类中读取一个文件。我的问题类似,但有两个不同之处。首先,我使用不同的项目布局: /src/com/company/project /资源 在resources文件夹中,我有一个名为“test.txt”的文件: /参考资料/test.txt 在项目文件夹中,我有一个类test.java /src/com/company/project/test.java 我希望mu java类能够以静态方法读取test.txt的内容。我尝试了以下方法: private static String p

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

/src/com/company/project
/资源

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

/参考资料/test.txt

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

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

我希望mu java类能够以静态方法读取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。如何在上面的代码段中正确声明我的项目设置文件的路径以及方法需要是静态的这一事实?

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

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


(但如果你把它打包成一个JAR,这就行不通了。)

这实际上取决于IDE如何从项目中生成输出。通常情况下,类加载器相对于调用类加载资源,但如果处理得当,“资源”最终将位于输出文件夹层次结构的“根”中,您可以相应地访问它们

例如,如果我用IntelliJ IDEA在名为
com/acme/TestClass.class
的类中重新创建代码,则在构建时会在IDE中生成以下输出结构。这假设“test.txt”位于一个名为“resources”的文件夹中,并且该文件夹被指定为“resources root”:

文本文件最终位于输出文件夹的根目录中,因此访问它很简单。当我尝试在
TestClass
中以静态方法加载文件时,以下代码对我有效:

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

其他答案中唯一没有提到的是,您的系统可能无法正常工作。如果项目上方的目录包含必须解码的字符,那么对“getResource”(“test.txt”).getFile()的调用将无法为您提供有效的java.io.File路径。

经过无休止的尝试,我放弃了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 "";
    }
}

无论openResource方法是静态的还是非静态的,无论是从项目内部调用还是从构建路径上的另一个项目调用,此技术都有效。

我从静态函数加载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();
}

resources
文件夹在类路径上吗?我不知道如何在eclipse中检查这个?resources文件夹是一个源文件夹,就像src一样。EclipseIDE中的java源文件夹只有两个子文件夹:src和resources。也许这就回答了这个问题?那么它应该可以工作了(我假设您使用的是Maven)。尝试将项目导出为
jar
,并查看它是否在文件中(根目录中)。使用stream.available()是有风险的,不能保证返回流的全部或任何长度。
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 "";
    }
}
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();
    }
}
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();
}