2014-06-02 14 views
2

Чтобы отобразить содержимое файла определенного каталога в пути к классам, я использую новые функции FileSystem и Path Java 7. В одном развертывании каталог хранится в файловой системе напрямую. В другом развертывании он сохраняется в файле JAR.Чтение из файловой системы через объект FileSystem

Мой подход хорошо работает с файлами JAR: создаю объект FileSystem, который ссылается на файл JAR и получает доступ к содержимому через объект Path.

 ... 
     URI dir = ... 
     String[] array = dir.toString().split("!"); 

     try (final FileSystem fs = FileSystems.newFileSystem(URI.create(array[0]), new HashMap<String, Object>())) 
     { 
      final Path directory = fs.getPath(array[1]); 
      try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(directory)) 
      { 
     ... 

Благодаря объекта дир имеет следующие значения, он работает:

jar:file:/C:/Users/pax/.../Detector-1.0.jar!/org/.../destinationdir 

Но в другой среде каталог назначения хранится в файловой системе, непосредственно. Объект реж содержит значение:

file:/C:/Users/pax/.../destinationdir 

FileSystems.newFileSystem(...) всегда бросает следующее исключение для / и file:/C:/Users/pax/.../destinationdir как URI:

java.lang.IllegalArgumentException: Path component should be '/' 
at sun.nio.fs.WindowsFileSystemProvider.checkUri(WindowsFileSystemProvider.java:68) 

Как вы используете FileSystem.newFileSystem для направления в файловой системе?

Есть ли лучший подход, чтобы перечислить содержимое каталогов независимо от его определенного типа хранилища (файловой системы или JAR-файла)?

ответ

2

После принятия резолюции Вопрос подчинена решению вопроса («назначения на файловой системе» против «назначения в JAR-файла») путем примерки уловов подхода: NIO2: how to generically map a URI to a Path? метод

Эта утилита пытается получить правильный Path экземпляр. Но может возникнуть еще одна проблема: если этот ресурс назначения содержится в файле JAR (вместо файловой системы), вы можете получить доступ только к ресурсу через связанный с ним экземпляр FileSystem, который не должен быть закрыт! Таким образом, ваш вспомогательный метод должен вернуть объект Path, а также экземпляр FileSystem (требуется только в случае, если он не находится в файловой системе напрямую). Вызывающий должен закрыть FileSystem объект вручную:

public static PathReference getPath(final URI resPath) throws IOException 
{ 
    try 
    { 
     // first try getting a path via existing file systems 
     return new PathReference(Paths.get(resPath), null); 
    } 
    catch (final FileSystemNotFoundException e) 
    { 
     /* 
     * not directly on file system, so then it's somewhere else (e.g.: 
     * JAR) 
     */ 
     final Map<String, ?> env = Collections.emptyMap(); 
     final FileSystem fs = FileSystems.newFileSystem(resPath, env); 
     return new PathReference(fs.provider().getPath(resPath), fs); 
    } 
} 

обертка класс PathReference должен реализовывать AutoClosable так, что он может быть использован в try блоке:

public class PathReference implements AutoCloseable 
{ 
    ... 
    @Override 
    public void close() throws Exception 
    { 
     if (this.fileSystem != null) 
      this.fileSystem.close(); 
    } 

    public Path getPath() 
    { 
     return this.path; 
    } 

    public FileSystem getFileSystem() 
    { 
     return this.fileSystem; 
    } 
} 

Это делает выпуск экземпляра FileSystem немного более прозрачным:

... 
try (final PathReference fileObj = SignatureUtils.getPath(file)) 
{ 
    ... 
    try (InputStream fileStream = Files.newInputStream(fileObj.getPath())) 
    { 
    ... 
Смежные вопросы