jar 中的 Java 访问文件导致 java.nio.file.FileSystemNotFoundException
Posted
技术标签:
【中文标题】jar 中的 Java 访问文件导致 java.nio.file.FileSystemNotFoundException【英文标题】:Java access files in jar causes java.nio.file.FileSystemNotFoundException 【发布时间】:2014-05-01 14:08:24 【问题描述】:在尝试使用我的 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)
....
这是我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);
webViewPresentation
目录位于我的 jar 的根目录中:
只有当我将我的应用程序打包为 jar 时才会出现此问题,在 Eclipse 中调试没有问题。我怀疑这与bug 有关,但我不确定如何解决此问题。
任何帮助表示赞赏
如果重要的话:
我正在使用 Java 8 build 1.8.0-b132
Windows 7 Ult. x64
【问题讨论】:
对于 jars ***.com/questions/5171957/access-file-in-jar-file 你必须做些不同的事情 答案中使用的方法读取单个文件为Stream
,我想复制整个目录。我添加了一个屏幕截图来澄清
也许你也想用Files.createTempDirectory
是的,我在我的 main()
某处这样做了
在 IDE (Eclipse) 中运行时,资源实际上是一个文件。如果您打包应用程序并尝试在 IDE 之外运行它,问题就会浮出水面。
【参考方案1】:
这可能是一个 hack,但以下对我有用:
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);
这使用了 ZipFileSystemProvider 在内部存储由 URI 打开的文件系统列表的事实。
【讨论】:
奇怪的是Paths.get(URI)
没有处理jar 文件路径的能力...【参考方案2】:
接受的答案不是最好的,因为当您在 IDE 中启动应用程序或资源是静态的并存储在类中时它不起作用! java.nio.file.FileSystemNotFoundException when getting file from resources folder提出了更好的解决方案
InputStream in = getClass().getResourceAsStream("/webViewPresentation");
byte[] data = IOUtils.toByteArray(in);
IOUtils 来自 Apache commons-io。
但是如果你已经在使用 Spring 并且想要一个文本文件,你可以将第二行更改为
StreamUtils.copyToString(in, Charset.defaultCharset());
StreamUtils.copyToByteArray 也存在。
【讨论】:
OP 试图获取Path
(可能是为了 NIO 中新的异步处理能力),而不是流或字符串,所以这不是答案。
它可能不是问题的答案,但确实 path/uri 解决方案无法使用,原因有两个:如果资源被解包,它不起作用,如果您从jar 同时 - 您只能打开一次文件系统......但是一般来说,您如何知道它是否是同一个文件系统?很多测试是必要的。这里的答案显示了一个简单而有效的解决方案。【参考方案3】:
如果您使用的是 spring 框架库,那么有一个简单的解决方案。
根据要求,我们要阅读 webViewPresentation; 我可以用下面的代码解决同样的问题:
URI uri = getClass().getResource("/webViewPresentation").toURI();
FileSystems.getDefault().getPath(new UrlResource(uri).toString());
【讨论】:
似乎不适用于嵌套 JAR 或BOOT-INF/classes
。【参考方案4】:
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]);
请注意,完成后您应该 .close()
您的 FileSystem
。
【讨论】:
是的,这不是很好的文档记录...如果这些路径不是来自同一个文件系统提供程序,您应该.resolve()
或 .relativize()
其他路径的 .toString()
值。 .. 我也被它所困扰(我正在通过 FTP 开发文件系统实现)
不确定它是否更好,但here you go :)
请注意,从那时起我开发了一些您可能感兴趣的东西;见here
@8odoros 你最好使用 .replaceFirst();您只想替换找到的第一个匹配项,而不是全部替换
这种方法可以使用嵌套的 jar,例如jar:file:outer.jar!/inner.jar!/file.txt
?以上是关于jar 中的 Java 访问文件导致 java.nio.file.FileSystemNotFoundException的主要内容,如果未能解决你的问题,请参考以下文章
解决在eclipse2021中,用mysql-connector-java-8.0.18.jar不兼容,导致无法访问数据库问题(2021-10-23)
错误记录Flutter 混合开发报错 ( java.nio.file.FileSystemException: xxx/R.jar: 另一个程序正在使用此文件,进程无法访问。 )