在使用nio加载文件时,在idea中运行没有问题,但打成jar包后在windows和linux下都有问题:
public static void main(String[] args) throws Exception{
// SpringApplication.run(MarketCollectApplication.class,args);
URI uri = MarketCollectApplication.class.getClassLoader().getResource("conf/sh.txt").toURI();
FileSystem aDefault = FileSystems.getDefault();
System.out.println(aDefault.getClass());
FileSystemProvider provider = FileSystems.getDefault().provider();
System.out.println(provider.getClass());
System.out.println("====================" + uri.getScheme());
List<FileSystemProvider> fileSystemProviders = FileSystemProvider.installedProviders();
fileSystemProviders.forEach(p -> {
System.out.println(p.getClass());
});
Path path = Paths.get(uri);
}
这种情况下在idea中没有问题:
class sun.nio.fs.WindowsFileSystem
class sun.nio.fs.WindowsFileSystemProvider
====================file
class sun.nio.fs.WindowsFileSystemProvider
class com.sun.nio.zipfs.ZipFileSystemProvider
但是在打成jar包运行时Path path = Paths.get(uri)这一行会抛出异常:
windows环境下:

linux环境下:

究其原因,是FileSystemProvider的使用问题,先看java.nio.file.Paths#get(java.net.URI):
public static Path get(URI uri) {
String scheme = uri.getScheme();
if (scheme == null)
throw new IllegalArgumentException("Missing scheme");
// check for default provider to avoid loading of installed providers
if (scheme.equalsIgnoreCase("file"))
return FileSystems.getDefault().provider().getPath(uri);
// try to find provider
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
if (provider.getScheme().equalsIgnoreCase(scheme)) {
return provider.getPath(uri);
}
}
throw new FileSystemNotFoundException("Provider \"" + scheme + "\" not installed");
}
uri.getScheme()在idea中是file,在打成jar包后变成了jar。
当前缀以file开头时,会使用FileSystems.getDefault().provider()来处理,这个provider在windows环境下是WindowsFileSystemProvider, 在linux环境下是LinuxFileSystemProvider。
FileSystemProvider.installedProviders()对应windows中的WindowsFileSystemProvider和ZipFileSystemProvider,对应linux中的LinuxFileSystemProvider和ZipFileSystemProvider。
当前缀不以file开头时,会使用FileSystemProvider.installedProviders()中与uri.getScheme()匹配的provider来处理,对应的就是ZipFileSystemProvider。
ZipFileSystemProvider对应的FileSystem需要自己创建,使用和创建方式参考:https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html
解决办法:在Path path = Paths.get(uri)中进行处理
Path path = null;
try{
path = Paths.get(uri);
}catch (Exception e){
//@see https://stackoverflow.com/questions/25032716/getting-filesystemnotfoundexception-from-zipfilesystemprovider-when-creating-a-p
//@see http://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html
FileSystem zipfs = FileSystems.newFileSystem(uri, env);
path = Paths.get(uri);
}
或者使用其他办法加载资源文件:
byte[] data;
try (InputStream in = getClass().getResourceAsStream("/elasticsearch/segmentsIndex.json")) {
data = IOUtils.toByteArray(in);
}




