简体   繁体   English

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

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

I want to read a file in my java class. 我想在我的java类中读取一个文件。 My question is similar to this one , but there are two differences. 我的问题类似于这个 ,但有两个不同之处。 first, I use a different project layout: 首先,我使用不同的项目布局:

/src/com/company/project / src目录/ COM /公司/项目
/resources /资源

In the resources folder I have a file called "test.txt": 在资源文件夹中,我有一个名为“test.txt”的文件:

/resources/test.txt /resources/test.txt

In the project folder I have a class test.java 在项目文件夹中,我有一个类test.java

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

I want mu java class to be able to read the contents of test.txt in a STATIC METHOD. 我希望mu java类能够在STATIC METHOD中读取test.txt的内容。 I've tried the following: 我尝试过以下方法:

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

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

        File file = new File(fileURL);


        ...
    }   
}

and the following paths: 以及以下路径:

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

But they all throw a FileNotFoundException when I want to read the file. 但是当我想要读取文件时,它们都会抛出FileNotFoundException。 How can I correctly declare the path to my file in the snippet above with respect to my project setup and the fact that the method needs to be static? 如何根据我的项目设置以及该方法需要静态的事实在上面的代码段中正确声明我的文件的路径?

After endless trials, I gave up on ClassLoader and getResource methods of any kind. 经过无休止的试验,我放弃了任何类型的ClassLoader和getResource方法。 Absolutely nothing worked, especially if the opening attempt was made from another project. 绝对没有任何效果,特别是如果开放尝试来自另一个项目。 I always ended up getting the bin folder instead of the src folder. 我总是得到bin文件夹而不是src文件夹。 So I devised the following work around: 所以我设计了以下工作:

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 "";
    }
}

The getProjectDir method returns the physical path of the project from which it was called, eg C:/workspace/MyProject/. getProjectDir方法返回调用它的项目的物理路径,例如C:/ workspace / MyProject /。 After that, all you need to do is concatenate the relative path in MyProject of your resource file to open the stream: 之后,您需要做的就是连接资源文件的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();
    }
}

This technique works whether the openResource method is static or non-static, and whether it is called from within the project or from another project on the build path. 无论openResource方法是静态还是非静态方法,以及是从项目内还是从构建路径上的其他项目调用,该方法都有效。

You should use the class loader of the class which is in the same JAR as the resource instead of the TCCL. 您应该使用与资源相同的JAR中的类的类加载器而不是TCCL。 And then you need to specify the name of the resource with a full path. 然后,您需要使用完整路径指定资源的名称。 And it is typically not good to access those as files. 通常不喜欢将它们作为文件访问。 Just open it directly for read (or copy it to a temp file if you need to): 只需直接打开它进行读取(如果需要,可将其复制到临时文件中):

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

BTW: if you simply want to open a file, you need to use a relative file name. 顺便说一句:如果您只是想打开一个文件,则需要使用相对文件名。 This is searched relative to the start dir, which is normally the project main dir (in eclipse): 这是相对于start dir搜索的,它通常是项目主目录(在eclipse中):

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

(but this wont work if you package it up as a JAR). (但如果你将它打包成JAR,这将不起作用)。

It really depends on how your IDE generates output from your project. 这实际上取决于IDE如何从项目中生成输出。 Typically, classloaders load resources relative to the invoking classes, but if treated right, 'resources' will just end up in the 'root' of your output folder hierarchy, and you can access them accordingly. 通常,类加载器相对于调用类加载资源,但如果处理正确,“资源”将最终位于输出文件夹层次结构的“根”中,您可以相应地访问它们。

For example, if I recreate your code in IntelliJ IDEA, in a class called com/acme/TestClass.class , the following output structure is generated within the IDE when building. 例如,如果我在IntelliJ IDEA中重新创建代码,则在名为com/acme/TestClass.class ,在构建时会在IDE中生成以下输出结构。 This assumes I have "test.txt" sitting in a folder I called "resources", and that folder is specified as being a "resources root": 这假设我将“test.txt”放在我称为“资源”的文件夹中,并将该文件夹指定为“资源根”:

/com
  /acme
    TestClass.class
test.txt

The text file ends up in the output folder's root, so accessing it is simple. 文本文件最终位于输出文件夹的根目录中,因此访问它很简单。 The following code works for me when I attempt to load the file in a static method within TestClass : 当我尝试在TestClass中的静态方法中加载文件时,以下代码适用于我:

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

The only thing not covered in the other answers is that your URL conversion to file might not work correctly. 其他答案中未涉及的唯一内容是您的URL转换为文件可能无法正常工作。 If the directories above your project contain a characters that must be decoded then your call to 'getResource("test.txt").getFile()' is not giving you a valid java.io.File path. 如果项目上方的目录包含必须解码的字符,那么调用'getResource(“test.txt”)。getFile()'不会给你一个有效的java.io.File路径。

I load shader for openGL ES from static function. 我从静态函数加载了用于openGL ES的着色器。

Remember you must use lower case for your file and directory name, or else the operation will be failed 请记住,您必须使用小写字母作为文件和目录名称,否则操作将失败

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() : "";
    }

    ...

}

Another method to convert input stream to string. 另一种将输入流转换为字符串的方法。

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.

相关问题 jar文件中的Java classLoader - Java classLoader within a jar file 静态方法中的java.io.FileNotFoundException(访问被拒绝)来移动文件 - java.io.FileNotFoundException (Access is Denied) in a static method to move file 如何使用Java中的类加载器从Web Inf资源文件夹中读取属性文件 - How to read properties file from web inf resource folder using classloader in java 如何在运行Java应用程序时使用classloader将目录指定为classpath以读取其中的文件? - How to specify the directory as classpath in order to read a file in it using classloader while running java application? spark-submit:传递java属性文件给出FileNotFoundException - spark-submit: Passing java properties file gives FileNotFoundException Java 使用公共 static void midi(Score score) 方法读取和播放 MIDI 文件 - Java Read and Play MIDI file using public static void midi(Score score) method Java如何从静态方法读取/写入类路径中的文件 - Java How to read/write a file in classpath from a static method 使用java属性文件时的FileNotFoundException - FileNotFoundException when using java properties file SAXParser 为 XML 文件提供 FileNotFoundException - SAXParser gives FileNotFoundException for XML file 尝试读取java中的.txt文件时,无法将FileNotFoundException解析为类型 - FileNotFoundException cannot be resolved to a type when trying to read a .txt file in java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM