如何从网络读取JarFile至内存,无需保存转换JarInputStream/byte[]为JarFile
不用落地本地,在内存中处理网络Jar文件的方案
嘿,这个需求我之前做插件更新的时候也碰到过!确实,JarFile这个类本身是绑定本地文件系统的——它的构造函数只接受文件路径、File对象或者ZipFile,没法直接从JarInputStream或者byte[]直接实例化。不过我们有几个不错的变通方案,能实现完全在内存中处理Jar内容,不用把文件存到本地磁盘。
方案一:直接用JarInputStream处理(最轻量化)
如果你的需求只是遍历Jar里的条目、读取资源文件或者类字节码,其实JarInputStream完全能满足,没必要非要转成JarFile。它可以直接从网络流中读取Jar内容,顺序处理每个条目。
结合你的代码片段,示例如下:
public static void update() throws Exception { String plid = "55283"; // 获取资源信息 HttpURLConnection conn = (HttpURLConnection) new URL("https://api.spiget.org/v2/resources/" + plid).openConnection(); JSONObject info = (JSONObject) new JSONParser().parse(new InputStreamReader(conn.getInputStream())); String downloadUrl = info.get("downloadUrl").toString(); // 下载Jar文件流并处理 HttpURLConnection downloadConn = (HttpURLConnection) new URL(downloadUrl).openConnection(); try (JarInputStream jarIn = new JarInputStream(downloadConn.getInputStream())) { JarEntry entry; // 遍历Jar里的所有条目 while ((entry = jarIn.getNextJarEntry()) != null) { if (!entry.isDirectory()) { // 读取条目的内容,比如读取类文件字节或配置文件 byte[] entryBytes = jarIn.readAllBytes(); // 这里可以做你需要的处理:比如加载类、解析资源等 System.out.println("处理条目:" + entry.getName()); } jarIn.closeEntry(); } } }
方案二:用内存文件系统模拟JarFile(实现随机访问)
如果你的业务逻辑必须依赖JarFile的API(比如需要随机访问某个条目,而不是顺序遍历),可以用Java 7引入的NIO内存文件系统,把Jar的字节数组挂载成一个内存中的虚拟文件系统,这样就能创建JarFile实例了。
示例代码:
import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; public static void update() throws Exception { String plid = "55283"; // 1. 获取下载链接并读取Jar字节数组 HttpURLConnection conn = (HttpURLConnection) new URL("https://api.spiget.org/v2/resources/" + plid).openConnection(); JSONObject info = (JSONObject) new JSONParser().parse(new InputStreamReader(conn.getInputStream())); String downloadUrl = info.get("downloadUrl").toString(); HttpURLConnection downloadConn = (HttpURLConnection) new URL(downloadUrl).openConnection(); byte[] jarBytes = downloadConn.getInputStream().readAllBytes(); // 2. 创建内存文件系统,将字节数组挂载为Jar Map<String, String> env = new HashMap<>(); env.put("create", "true"); try (FileSystem fs = FileSystems.newFileSystem(Paths.get("temp.jar"), jarBytes, env)) { // 用JarFile实例操作内存中的Jar try (JarFile jarFile = new JarFile(fs.getPath("/").toFile())) { // 随机访问某个条目,比如插件配置文件 JarEntry entry = jarFile.getEntry("plugin.yml"); if (entry != null) { try (InputStream in = jarFile.getInputStream(entry)) { byte[] content = in.readAllBytes(); System.out.println("读取到plugin.yml内容:" + new String(content)); } } // 也可以遍历所有条目 jarFile.stream().forEach(jarEntry -> { if (!jarEntry.isDirectory()) { System.out.println("Jar内文件:" + jarEntry.getName()); } }); } } }
为什么不能直接转JarFile?
简单说,JarFile底层依赖随机访问文件的能力(比如快速定位到某个条目的位置),而JarInputStream是顺序流,只能从头到尾读取;byte[]虽然是内存中的数据,但JarFile没有提供直接从字节数组构造的方法。内存文件系统的本质是把字节数组模拟成一个可随机访问的“虚拟文件”,满足JarFile的构造要求。
内容的提问来源于stack exchange,提问作者Richee Nektar
相关产品推荐
相关产品推荐

