我想从我的罐子里像这样读一个资源:

File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));

//Read the file

当在Eclipse中运行它时,它工作得很好,但如果我将它导出到一个jar,然后运行它,会有一个IllegalArgumentException:

Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical

我真的不知道为什么,但通过一些测试,我发现如果我改变了

file = new File(getClass().getResource("/file.txt").toURI());

to

file = new File(getClass().getResource("/folder/file.txt").toURI());

然后它反过来工作(它在jar中工作,但在eclipse中不工作)。

我正在使用Eclipse,文件所在的文件夹位于类文件夹中。


当前回答

要访问jar中的文件,你有两个选择:

将文件放在与你的包名匹配的目录结构中(在提取.jar文件后,它应该与.class文件在同一个目录中),然后使用getClass().getResourceAsStream("file.txt")访问它 将文件放在根目录(在提取。jar文件后,它应该在根目录中),然后使用Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")访问它

当jar作为插件使用时,第一个选项可能不起作用。

其他回答

问题是某些第三方库需要文件路径名而不是输入流。大多数答案都没有提到这个问题。

在这种情况下,一种解决方法是将资源内容复制到临时文件中。下面的例子使用了jUnit的TemporaryFolder。

    private List<String> decomposePath(String path){
        List<String> reversed = Lists.newArrayList();
        File currFile = new File(path);
        while(currFile != null){
            reversed.add(currFile.getName());
            currFile = currFile.getParentFile();
        }
        return Lists.reverse(reversed);
    }

    private String writeResourceToFile(String resourceName) throws IOException {
        ClassLoader loader = getClass().getClassLoader();
        InputStream configStream = loader.getResourceAsStream(resourceName);
        List<String> pathComponents = decomposePath(resourceName);
        folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
        File tmpFile = folder.newFile(resourceName);
        Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
        return tmpFile.getAbsolutePath();
    }

你可以使用类加载器从类路径中读取根路径(开头没有“/”)

InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

我找到了解决办法

BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));

将“Main”替换为您编写它的java类。将“path”替换为jar文件中的路径。

例如,如果你把State1.txt放在com.issac包中。如果你运行的是Linux或Mac,那么输入路径为“/com/issac/state/State1”。如果你运行的是Windows,那么输入路径为“\com\issac\state\State1”。除非出现“文件未找到”异常,否则不要将.txt扩展名添加到文件中。

到目前为止(2017年12月),这是我发现的唯一一个在IDE内部和外部都可以工作的解决方案。

使用PathMatchingResourcePatternResolver

注意:它也适用于spring-boot

在这个例子中,我读取了src/main/resources/my_folder中的一些文件:

try {
    // Get all the files under this inner resource folder: my_folder
    String scannedPackage = "my_folder/*";
    PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
    Resource[] resources = scanner.getResources(scannedPackage);

    if (resources == null || resources.length == 0)
        log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
    else {
        for (Resource resource : resources) {
            log.info(resource.getFilename());
            // Read the file content (I used BufferedReader, but there are other solutions for that):
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                // ...
                // ...                      
            }
            bufferedReader.close();
        }
    }
} catch (Exception e) {
    throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}

确保使用正确的分隔符。我用File.separator替换了相对路径中的all /。这在IDE中工作得很好,但是在构建JAR中却不行。