创建资源路径时,使用ZipFileSystemProvider会出现FileSystemNotFoundException。

55

我有一个Maven项目,在一个方法内部,我想为我的资源文件夹创建一个路径。这样做的方法如下:

try {
    final URI uri = getClass().getResource("/my-folder").toURI();
    Path myFolderPath = Paths.get(uri);
} catch (final URISyntaxException e) {
    ...
}

生成的URI看起来像jar:file:/C:/path/to/my/project.jar!/my-folder

堆栈跟踪如下:

Exception in thread "pool-4-thread-1" java.nio.file.FileSystemNotFoundException
    at com.sun.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:171)
    at com.sun.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:157)
    at java.nio.file.Paths.get(Paths.java:143)

URI看起来是有效的。在!之前的部分指向生成的jar文件,之后的部分指向存档根目录中的my-folder。我以前已经使用过这些说明来创建到我的资源的路径。为什么现在会出现异常?


Zip文件格式是否可被ZipFileSystemProvider读取? - Uwe Allner
1
该文件夹存在于根目录中。而且这个jar文件是由Maven生成的,因此应该是可读的。 - stevecross
如果您已经有了URL,则不需要FilePath来读取其内容。您只需调用URL.openStream()并从该方法返回的InputStream中读取即可。如果您确实必须拥有FilePath对象,则需要下面提到的FileSystem修复程序。但是,大多数事情实际上不需要文件,并且可以处理InputStreamReader接口,因此如果可能的话,我建议首先使用URL.openStream()路线。 - Shadow Man
4个回答

74

我正在使用相同的技术来访问一个jar文件。但是我面临的问题是,每当路径中有空格字符时,我就会遇到相同的错误。否则它可以正常工作。 - frewper
是的,在文件路径中使用空格和ASCII范围之外的字符会导致nio出现问题。当jar/zip文件中的文件包含这些字符时也会出现问题。但这是一个不同的问题,您可以在此处寻求帮助:https://dev59.com/xZjga4cB1Zd3GeqPGzX5 - Uwe Allner

14

如果你想要读取资源文件,你可以直接使用getClass.getResourceAsStream方法。这将会隐式地设置文件系统。 如果你的资源文件找不到,该方法将返回null,否则你将直接获得一个输入流来解析你的资源。


13

扩展 @Uwe Allner 的优秀答案,一个可靠的方法是:

private FileSystem initFileSystem(URI uri) throws IOException
{
    try
    {
        return FileSystems.getFileSystem(uri);
    }
    catch( FileSystemNotFoundException e )
    {
        Map<String, String> env = new HashMap<>();
        env.put("create", "true");
        return FileSystems.newFileSystem(uri, env);
    }
}

在加载URI之前使用此功能可确保文件系统处于工作状态。我总是在使用完毕后调用FileSystem.close()

FileSystem zipfs = initFileSystem(fileURI);
filePath = Paths.get(fileURI);
// Do whatever you need and then close the filesystem
zipfs.close();

3
注意,ZipFileSystem 可以被关闭,但 WindowsFileSystem 会报错。 - Brad Turek

10

除了@Uwe Allner和@mvreijn之外:

要注意URI的格式。有时候URI格式错误(例如"file:/path/..."),正确的格式应该是"file:///path/..."),这会导致无法获得正确的FileSystem
在这种情况下,从PathtoUri()方法创建URI会有所帮助。

在我的案例中,我稍微修改了initFileSystem方法,并在非异常情况下使用FileSystems.newFileSystem(uri, Collections.emptyMap())。 在异常情况下,使用FileSystems.getDefault()

在我的案例中,还需要捕获IllegalArgumentException以处理Path component should be '/'的情况。在Windows和Linux上可以捕获异常,但FileSystems.getDefault()仍然有效。 在OSX上不会发生异常,并且将创建newFileSystem

private FileSystem initFileSystem(URI uri) throws IOException {
    try {
        return FileSystems.newFileSystem(uri, Collections.emptyMap());
    }catch(IllegalArgumentException e) {
        return FileSystems.getDefault();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接