Получение FileSystemNotFoundException из ZipFileSystemProvider при создании пути к ресурсу
У меня есть проект 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
.
Элемент stacktrace выглядит следующим образом:
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
в корневом каталоге архива. Ранее я использовал эти инструкции для создания путей к моим ресурсам. Почему теперь я получаю исключение?
Ответы
Ответ 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
Ответ 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();
Ответ 4
В дополнение к @Uwe Allner и @mvreijn:
Будьте осторожны с URI
. Иногда URI
имеет неправильный формат (например, "file:/path/..."
, а правильный - "file:///path/..."
), и вы не можете получить правильный FileSystem
.
В этом случае помогает URI
создать метод Path
toUri()
.
В моем случае я немного изменил метод 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();
}
}