【问题标题】:Getting FileSystemNotFoundException from ZipFileSystemProvider when creating a path to a resource创建资源路径时从 ZipFileSystemProvider 获取 FileSystemNotFoundException
【发布时间】:2014-07-30 09:02:42
【问题描述】:

我有一个 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 可读?
  • 文件夹存在于根目录下。并且jar文件是由Maven生成的,因此它应该是可读的。
  • 如果您已经拥有URL,则不需要FilePath 即可阅读其内容。您只需调用URL.openStream() 并从该方法返回的InputStream 中读取。如果您确实必须拥有FilePath 对象,那么您将需要下面提到的FileSystem 修复。但是大多数东西并不真正需要文件并且可以处理InputStreamReader 接口,所以如果可能的话,我建议先走URL.openStream() 路线。

标签: java maven


【解决方案1】:

您需要先创建文件系统,然后才能访问 zip 中的路径,例如

final URI uri = getClass().getResource("/my-folder").toURI();
Map<String, String> env = new HashMap<>(); 
env.put("create", "true");
FileSystem zipfs = FileSystems.newFileSystem(uri, env);
Path myFolderPath = Paths.get(uri);

这不是自动完成的。

http://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html

【讨论】:

  • 我正在使用相同的技术来访问 jar 文件。但我面临的问题是,只要路径中有空格字符,我就会得到同样的错误。否则效果很好
  • 是的,文件路径中超出 ASCII 范围的空格和字符会导致 nio 出现问题。此外,当 jar/zip 中的文件具有这些字符时。但这是一个不同的问题,您可以在这里找到帮助:stackoverflow.com/questions/37936627/…
【解决方案2】:

如果你打算读取资源文件,可以直接使用getClass.getResourceAsStream。这将隐式设置文件系统。 如果找不到您的资源,该函数返回null,否则您直接有一个输入流来解析您的资源。

【讨论】:

    【解决方案3】:

    扩展@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();
    

    【讨论】:

    • 小心,ZipFileSystem 可以关闭,但WindowsFileSystem 会报错。
    【解决方案4】:

    除了@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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-12
      • 1970-01-01
      • 2011-09-12
      • 1970-01-01
      • 2016-02-09
      • 1970-01-01
      • 1970-01-01
      • 2020-12-09
      相关资源
      最近更新 更多