通过 FileSystem 对象从文件系统读取

PAX*_*PAX 2 java filesystems directory jar path

为了列出类路径上特定目录的文件内容,我使用了 Java 7 的新FileSystem功能Path。在一个部署中,该目录直接存储在文件系统上。在另一个部署中,它存储在 JAR 文件中。

我的方法适用于 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))
            {
        ...
Run Code Online (Sandbox Code Playgroud)

由于 dir 对象具有以下值,因此它可以工作:

jar:file:/C:/Users/pax/.../Detector-1.0.jar!/org/.../destinationdir
Run Code Online (Sandbox Code Playgroud)

但在其他环境中,目标目录直接存储在文件系统上。dir 对象包含值:

file:/C:/Users/pax/.../destinationdir
Run Code Online (Sandbox Code Playgroud)

FileSystems.newFileSystem(...)/始终为file:/C:/Users/pax/.../destinationdirURI抛出以下异常:

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

如何使用FileSystem.newFileSystem文件系统上的目的地?

是否有更好的方法来独立于其特定类型的存储(文件系统或 JAR 文件)列出目录内容?

PAX*_*PAX 5

以下问题的解决方案通过 try-catch 方法解决了该问题(“文件系统上的目标”与“JAR 文件中的目标”):NIO2:如何一般地将 URI 映射到路径?

此实用程序方法尝试获取正确的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

包装类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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这使得实例的释放FileSystem更加透明:

...
try (final PathReference fileObj = SignatureUtils.getPath(file))
{
    ...
    try (InputStream fileStream = Files.newInputStream(fileObj.getPath()))
    {
    ...
Run Code Online (Sandbox Code Playgroud)