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

use*_*155 3 java file classloader

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

/src/com/company/project
/resources

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

/资源/测试.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);


        ...
    }   
}
Run Code Online (Sandbox Code Playgroud)

以及以下路径:

File file1 = new File("test.txt");
File file2 = new File("/test.txt");
File file3 = new File("/resources/test.txt");
Run Code Online (Sandbox Code Playgroud)

但是当我想读取文件时,它们都会抛出 FileNotFoundException 。如何根据我的项目设置以及该方法需要是静态的这一事实,在上面的代码片段中正确声明我的文件的路径?

eck*_*kes 5

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

InputStream is =
  Project.class.getClassLoader().getResourceAsStream("/resource/test.txt");
Run Code Online (Sandbox Code Playgroud)

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

File resource = new File("resource/test.txt");
Run Code Online (Sandbox Code Playgroud)

(但如果您将其打包为 JAR,这将不起作用)。


小智 5

经过无休止的尝试后,我放弃了任何类型的 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 "";
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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