bigywater.tech
Java · 248

ZIP 文件系统:把压缩包当作 Path 来访问

JDK 自带的 zip 文件系统让 zip 与 jar 像目录一样用 Files 和 Path 操作。这篇逐项真实运行:创建、列出、修改、何时写盘、多版本 jar 的 releaseVersion 与重复打开。

22 → 743 字节
close() 之前 / 之后磁盘上 a.zip 的大小
53 ms
往 50 MB 的 zip 加一个条目后 close() 的耗时
264 / 298 / 322
releaseVersion=8 / 17 / 21 读到同一路径的字节数

创建、列出与读取

实测 · 本机执行输出
  在 zip 文件系统里创建后、close() 之前,磁盘上的 a.zip 是否存在:true,大小 22 字节
  fs.provider().getScheme() = jar,isReadOnly = false,根目录 = /,separator = /
  close() 之后 a.zip 存在,大小 743 字节
  Files.walk 看到:[/, /bin.dat, /docs, /docs/readme.txt, /docs/sub, /docs/sub/中文.txt]
  readme.txt 大小 2400 字节,isDirectory = false;读出前 12 字符「hello zipfs」;中文文件名读出:你好
  关闭之后再用 Path → ClosedFileSystemException
  用 Python zipfile 读同一个文件验证: [('docs/', 0, 0, 0), ('docs/sub/', 0, 0, 0), ('docs/readme.txt', 2400, 34, 8), ('docs/sub/中文.txt', 6, 8, 8), ('bin.dat', 1000, 11, 8)]

修改已有 zip

实测 · 本机执行输出
  生成 200 个各 256 KB 随机内容的条目,zip 大小 50 MB
  默认(堆里缓存)往已有 50 MB 的 zip 里加一个 10 字节的条目:打开 0 ms;close() 耗时 53 ms;这个线程分配 599 KB;close 之前磁盘文件的修改时间没变 = true;close 之后文件大小 52471559 字节(之前 52471402)
  close 前后 a.zip 的 fileKey 是否相同(同一个 inode)= false(true 表示原文件被就地改写,false 表示换了新文件)
  默认                 往 50 MB 的 zip 里写 40 个 256 KB 的条目(共 10 MB)后、close 之前做一次 GC,文件系统还开着时多占的堆:0 MB;整个过程(含 close)67 ms
  useTempFile=true   往 50 MB 的 zip 里写 40 个 256 KB 的条目(共 10 MB)后、close 之前做一次 GC,文件系统还开着时多占的堆:0 MB;整个过程(含 close)75 ms
  4 MB 全零:noCompression=true 时 zip 4194462 字节;默认(压缩)4238 字节

多版本 jar 与重复打开

实测 · 本机执行输出
  jar 里有 /lib/Impl.class
  jar 里有 /META-INF/versions/21/lib/Impl.class
  jar 里有 /META-INF/versions/17/lib/Impl.class
  jar 里有 /META-INF/MANIFEST.MF
  releaseVersion=8:读 /lib/Impl.class 得到 264 字节(版本化条目大小不同,说明取到了对应版本)
  releaseVersion=17:读 /lib/Impl.class 得到 298 字节(版本化条目大小不同,说明取到了对应版本)
  releaseVersion=21:读 /lib/Impl.class 得到 322 字节(版本化条目大小不同,说明取到了对应版本)
  releaseVersion=runtime:读 /lib/Impl.class 得到 322 字节(版本化条目大小不同,说明取到了对应版本)
  同一个 jar 同时用 newFileSystem(Path) 打开两次 → 成功(两个独立实例)
  用 jar: URI 打开同一个 jar 第二次 → FileSystemAlreadyExistsException
  FileSystems.getFileSystem(uri) 得到的与 f1 是同一个对象 = true

分步演示

ZIP 文件系统
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS;50 MB 的测试 zip 由随机数据构成
    • 没有验证:zip64 与超过 4 GB 的条目、加密 zip、compressionMethod 属性的其它值、useTempFile 在真正大文件上的内存差别(这个测试里没有看到差别)、并发修改同一个 zip 的行为、Windows 上的文件锁与替换行为
    京ICP备2026067502号-1京公网安备11010502063487号