jar中的Java访问文件导致java.nio.file.FileSystemNotFoundException

tom*_*136 45 java nio java-7

在尝试使用我的java应用程序将jar文件中的某些文件复制到临时目录时,会抛出以下异常:

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(Unknown Source)
    at com.sora.util.walltoggle.pro.WebViewPresentation.setupTempFiles(WebViewPresentation.java:83)
   ....
Run Code Online (Sandbox Code Playgroud)

这是我的一小部分setupTempFiles(带行号):

81. URI uri = getClass().getResource("/webViewPresentation").toURI();
//prints: URI->jar:file:/C:/Users/Tom/Dropbox/WallTogglePro.jar!/webViewPresentation
82. System.out.println("URI->" + uri );
83. Path source = Paths.get(uri);
Run Code Online (Sandbox Code Playgroud)

webViewPresentation目录位于我的jar的根目录中:

在此输入图像描述

当我将我的应用程序打包为jar时,此问题才会退出,在Eclipse中进行调试没有问题.我怀疑这与这个bug有关,但我不确定如何纠正这个问题.

任何帮助赞赏

如果事项:

我在Java 8 build 1.8.0-b132上

Windows 7 Ult.64位

fge*_*fge 51

A FileSystemNotFoundException表示无法自动创建文件系统; 你还没有在这里创建它.

鉴于你的URI,你应该做的是拆分!,使用之前的部分打开文件系统,然后从以下部分获取路径!:

final Map<String, String> env = new HashMap<>();
final String[] array = uri.toString().split("!");
final FileSystem fs = FileSystems.newFileSystem(URI.create(array[0]), env);
final Path path = fs.getPath(array[1]);
Run Code Online (Sandbox Code Playgroud)

需要注意的是,你应该.close()FileSystem一旦你用它做.

  • 是的,这是一个没有很好记录的东西...如果这些路径不是来自同一个文件系统提供者,你应该``.resolve()`或`.relativize()`其他路径的`.toString()`值...我也被我咬了(我正在通过FTP开发FileSystem实现) (4认同)
  • 请注意,从那时起,我开发了一些您可能感兴趣的东西;见[这里](https://github.com/fge/java7-fs-more) (2认同)
  • 这种方法可以与嵌套jar一起使用吗,例如`jar:file:outer.jar!/inner.jar!/ file.txt`? (2认同)

Kin*_*rui 8

接受的答案不是最好的,因为当您在 IDE 中启动应用程序或资源是静态的并存储在类中时它不起作用!从资源文件夹中获取文件时,java.nio.file.FileSystemNotFoundException中提出了更好的解决方案

InputStream in = getClass().getResourceAsStream("/webViewPresentation");
byte[] data = IOUtils.toByteArray(in);
Run Code Online (Sandbox Code Playgroud)

IOUtils 来自 Apache commons-io。

但是如果你已经在使用 Spring 并且想要一个文本文件,你可以将第二行更改为

StreamUtils.copyToString(in, Charset.defaultCharset());
Run Code Online (Sandbox Code Playgroud)

StreamUtils.copyToByteArray 也存在。

  • OP 试图获得一个 `Path`(大概是为了 NIO 中的新异步处理功能),而不是一个流或一个字符串,所以这不是答案。 (4认同)

fue*_*mf5 5

这可能是一个黑客,但以下对我有用:

URI uri = getClass().getResource("myresourcefile.txt").toURI();

if("jar".equals(uri.getScheme())){
    for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
        if (provider.getScheme().equalsIgnoreCase("jar")) {
            try {
                provider.getFileSystem(uri);
            } catch (FileSystemNotFoundException e) {
                // in this case we need to initialize it first:
                provider.newFileSystem(uri, Collections.emptyMap());
            }
        }
    }
}
Path source = Paths.get(uri);
Run Code Online (Sandbox Code Playgroud)

这使用了 ZipFileSystemProvider 在内部存储由 URI 打开的文件系统列表的事实。

  • 奇怪的是 `Paths.get(URI)` 没有包含处理 jar 文件路径的能力...... (6认同)