使用FileSystems.getFileSystem获取ZipFileSystem时抛出FileSystemNotFoundException
关于直接获取ZipFileSystem的问题
首先直接给结论:你不能直接通过FileSystems.getFileSystem()获取磁盘上已存在的Zip文件对应的FileSystem,除非这个FileSystem已经被JVM初始化并注册过——这就是为什么你先调用newFileSystem()之后再用getFileSystem()就能正常运行的原因。
背后的原因
Java的ZipFileSystemProvider采用"按需注册"的机制:只有当你显式调用newFileSystem()去打开一个Zip文件时,它才会创建对应的FileSystem实例,并把这个实例注册到JVM的FileSystem注册表中。而getFileSystem()的作用仅仅是查找已经注册过的FileSystem,如果目标Zip文件的FileSystem还没被创建注册,自然就会抛出FileSystemNotFoundException。
正确的处理方式
最稳妥的做法是先尝试获取FileSystem,如果捕获到异常再去创建它,这样既避免了重复创建,又能处理首次访问的场景。示例代码如下:
import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class ZipFileSystemHandler { public static FileSystem getOrCreateZipFileSystem(Path zipPath) throws Exception { String zipUri = "jar:" + zipPath.toUri(); try { // 先尝试获取已注册的FileSystem return FileSystems.getFileSystem(URI.create(zipUri)); } catch (FileSystemNotFoundException e) { // 如果未注册,创建新的FileSystem Map<String, String> env = new HashMap<>(); // "create"设为"false"表示只读打开,若需要写入可改为"true" env.put("create", "false"); return FileSystems.newFileSystem(URI.create(zipUri), env); } } public static void main(String[] args) throws Exception { Path zipPath = Paths.get("your/zip/file/path.zip"); try (FileSystem zipFs = getOrCreateZipFileSystem(zipPath)) { // 在这里操作Zip文件,比如读取内部文件 Path internalFile = zipFs.getPath("internal/file.txt"); // ... 你的业务代码 } } }
额外注意事项
- URI格式要正确:必须使用
jar:file:///xxx.zip这种格式,不能直接用文件的原始URI,一定要加上jar:前缀。 - 记得关闭FileSystem:使用完后调用
close()释放资源,推荐用try-with-resources语法(如上例),它会自动帮你关闭FileSystem,避免文件被占用的问题。 - 写入场景的配置:如果你需要修改Zip文件(比如添加、删除内部文件),要把
env中的create设为"true",同时确保Zip文件没有被其他进程占用。
内容的提问来源于stack exchange,提问作者Franz
相关产品推荐
相关产品推荐

