神奇好望角 The Magical Cape of Good Hope

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

          基于 NIO2 的 ZIP 文件系統

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

          以前我曾用兩個類(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)) {
                              // 此處省略若干行。
                          }
                      }
                  }
              

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


          評論

          # re: 基于 NIO2 的 ZIP 文件系統  回復  更多評論   

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

          更正:pos == (syntaxAndInput.length()-1)
          主站蜘蛛池模板: 宁海县| 韶山市| 图木舒克市| 同德县| 淅川县| 永修县| 叶城县| 连平县| 南雄市| 凌海市| 常宁市| 历史| 明溪县| 光泽县| 衡南县| 获嘉县| 雅江县| 霍邱县| 平南县| 武威市| 唐海县| 浪卡子县| 措勤县| 北海市| 宜黄县| 轮台县| 浦北县| 富裕县| 会宁县| 溧阳市| 夏河县| 广州市| 祥云县| 昆山市| 金堂县| 拉孜县| 鹿泉市| 青冈县| 龙游县| 无棣县| 万源市|