神奇好望角 The Magical Cape of Good Hope

          庸人不必自擾,智者何需千慮?
          posts - 26, comments - 50, trackbacks - 0, articles - 11
            BlogJava :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理

          基于 NIO2 的 ZIP 文件系統(tǒng)

          Posted on 2011-12-01 13:12 蜀山兆孨龘 閱讀(2429) 評論(1)  編輯  收藏 所屬分類: Java SE

          以前我曾用兩個類(ZipItemZipSystem)實現(xiàn)了一個簡單的 ZIP 文件系統(tǒng)(以下簡稱 ZFS)。其實這兩個小類挺好用的,而且支持嵌套的 ZIP 文件,但是,但是……JDK 7 丟下來一枚叫做 NIO2 的笑氣炸彈,引入了一套標準的文件系統(tǒng) API,我承認我中彈了,手癢了,又根據(jù)這套 API 重新實現(xiàn)了 ZIP 文件系統(tǒng),終于在今天初步完工,哈。

          話說,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 沒有經(jīng)過代碼審閱、沒有經(jīng)過測試、沒有經(jīng)過……然后,@author Xueming Shen,真是丟咱華夏民族的臉……

          下面列個表格詳細比較官方 ZFS 和山寨 ZFS:

          比較內(nèi)容 官方 ZFS 山寨 ZFS
          實現(xiàn)方式 另起爐灶,用純 Java 重新實現(xiàn)了對 ZIP 文件格式的處理代碼。 基于 ZipFileZipInputStream 這兩個已經(jīng)穩(wěn)定多年的類,但涉及了大量本地代碼調(diào)用,也許會影響性能。
          讀操作 支持,且通過解壓到臨時文件支持隨機訪問。 支持,但不支持隨機訪問。
          寫操作 通過解壓到臨時文件進行支持,但無法檢測到其他進程對同一個 ZIP 文件的寫操作,不適用于并發(fā)環(huán)境。 不支持。ZIP 文件事實上是一個整體,對內(nèi)部條目的任何修改都可能導(dǎo)致重構(gòu)整個文件,因此所謂的寫操作必須通過臨時文件來處理,效率低下,意義不大,而且難以處理嵌套 ZIP 文件。這也符合我的原則:不解壓。
          嵌套 ZIP 文件 不支持。 支持,當然讀取嵌套 ZIP 文件會慢一些。
          反斜線分隔符 不支持,直接瓜掉。 支持,且和標準的斜線分隔符區(qū)別對待。例如,/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);
                  // 默認目錄,用于創(chuàng)建和解析相對路徑。默認為“/”。
                  env.put("defaultDirectory", "/dir/");
          
                  // 從文件創(chuàng)建一個 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")) {
                          // 創(chuàng)建一個嵌套的 ZFS。
                          try (FileSystem nestedZfs = zfs.provider().newFileSystem(path, env)) {
                              // 此處省略若干行。
                          }
                      }
                  }
              

          最后雙手奉上源代碼:請猛擊此處!


          評論

          # re: 基于 NIO2 的 ZIP 文件系統(tǒng)  回復(fù)  更多評論   

          2011-12-09 11:34 by 張寅中
          // 丫的,pos == syntaxAndInput.length()?!誰寫的?抓出來鞭尸。

          更正:pos == (syntaxAndInput.length()-1)
          主站蜘蛛池模板: 乌恰县| 从化市| 平安县| 靖边县| 讷河市| 丹寨县| 华坪县| 玛沁县| 开江县| 弥勒县| 青州市| 宁城县| 恭城| 九江县| 高邑县| 商水县| 江阴市| 哈密市| 芜湖市| 改则县| 灵寿县| 玉环县| 阳东县| 锦屏县| 镶黄旗| 光泽县| 孟津县| 八宿县| 和田市| 宜良县| 富平县| 玛曲县| 昭觉县| 甘肃省| 化州市| 鹤峰县| 横峰县| 尼勒克县| 文山县| 邳州市| 昌江|