基于 NIO2 的 ZIP 文件系统

以前我曾用两个类(ZipItemZipSystem)实现了一个简单的 ZIP 文件系统(以下简称 ZFS)。其实这两个小类挺好用的,而且支持嵌套的 ZIP 文件,但是,但是……JDK 7 丢下来一枚叫做 NIO2 的笑气炸弹,引入了一套标准的文件系统 API,我承认我中弹了,手痒了,又根据这套 API 重新实现了 ZIP 文件系统,终于在今天初步完工,哈。

话说,JDK 7 其实捆绑销售了一个 ZFS,demo 目录下还有源代码。可……它达不到我的奢求,而且 BUG 不少。随便逮两个:

        // com.sun.nio.zipfs.ZipFileSystemProvider 类中的方法
        @Override
        public Path getPath(URI uri) {

            String spec = uri.getSchemeSpecificPart();
            int sep = spec.indexOf("!/");
            if (sep == -1)
                throw new IllegalArgumentException("URI: "
                    + uri
                    + " does not contain path info ex. jar:file:/c:/foo.zip!/BAR");
            // 难怪该方法始终抛 IllegalArgumentException 异常,原来你小子把文件的 URI
            // 当成 ZFS 的 URI 在用……
            return getFileSystem(uri).getPath(spec.substring(sep + 1));
        }

        // com.sun.nio.zipfs.ZipFileSystem 类中的方法
        @Override
        public PathMatcher getPathMatcher(String syntaxAndInput) {
            int pos = syntaxAndInput.indexOf(':');
            // 丫的,pos == syntaxAndInput.length()?!谁写的?抓出来鞭尸。
            if (pos <= 0 || pos == syntaxAndInput.length()) {
                throw new IllegalArgumentException();
    

很明显,官方 ZFS 没有经过代码审阅、没有经过测试、没有经过……然后,@author Xueming Shen,真是丢咱华夏民族的脸……

下面列个表格详细比较官方 ZFS 和山寨 ZFS:

比较内容 官方 ZFS 山寨 ZFS
实现方式 另起炉灶,用纯 Java 重新实现了对 ZIP 文件格式的处理代码。 基于 ZipFileZipInputStream 这两个已经稳定多年的类,但涉及了大量本地代码调用,也许会影响性能。
读操作 支持,且通过解压到临时文件支持随机访问。 支持,但不支持随机访问。
写操作 通过解压到临时文件进行支持,但无法检测到其他进程对同一个 ZIP 文件的写操作,不适用于并发环境。 不支持。ZIP 文件事实上是一个整体,对内部条目的任何修改都可能导致重构整个文件,因此所谓的写操作必须通过临时文件来处理,效率低下,意义不大,而且难以处理嵌套 ZIP 文件。这也符合我的原则:不解压。
嵌套 ZIP 文件 不支持。 支持,当然读取嵌套 ZIP 文件会慢一些。
反斜线分隔符 不支持,直接瓜掉。 支持,且和标准的斜线分隔符区别对待。例如,/abc//abc\ 算不同的文件,实际上这两个能够并存于 ZIP 文件中。
空目录名 不支持,直接瓜掉。 支持。例如 /a/b/a//b 是两个可以并存且不同的文件。

山寨 ZFS 的用法示例:

        Map<String, Object> env = new HashMap<>();
        // 用于解码 ZIP 条目名。默认为 Charset.defaultCharset()。
        env.put("charset", StandardCharsets.UTF_8);
        // 指示是否自动探测嵌套的 ZIP 文件。默认为 false。
        env.put("autoDetect", true);
        // 默认目录,用于创建和解析相对路径。默认为“/”。
        env.put("defaultDirectory", "/dir/");

        // 从文件创建一个 ZFS。
        try (FileSystem zfs = FileSystems.newFileSystem(
                URI.create("zip:" + Paths.get("docs.zip").toUri()), env)) {
            Path path = zfs.getPath("app.jar");
            if ((Boolean) Files.getAttribute(path, "isZip")) {
                // 创建一个嵌套的 ZFS。
                try (FileSystem nestedZfs = zfs.provider().newFileSystem(path, env)) {
                    // 此处省略若干行。
                }
            }
        }
    

最后双手奉上源代码:请猛击此处!

你可能感兴趣的:(基于 NIO2 的 ZIP 文件系统)