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

时间:2014-06-02 18:16:58

标签: java jar path directory filesystems

为了列出类路径上特定目录的文件内容,我使用的是Java 7的新FileSystemPath功能。在一个部署中,目录直接存储在文件系统中。在另一个部署中,它存储在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))
            {
        ...

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

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

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

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文件)列出目录内容?

1 个答案:

答案 0 :(得分:3)

以下问题的解决方案通过try-catch方法处理问题(&#34;目标在文件系统&#34;与#34;目标在JAR文件&#34;中):NIO2: how to generically map a URI to a Path? < / p>

此实用程序方法尝试获取正确的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()))
    {
    ...