java实现读取jar包中配置文件的几种方式

 更新时间:2023年06月15日 11:33:43   作者:奔跑吧人生  
本文主要介绍了java实现读取jar包中配置文件的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

概述

在编程的某些情况下,我们需要读取jar包中的文件,这种情况要区别于我们平时使用类加载器读取配置文件,这个时候配置在jar包中,就能读取到,但是配置文件也可以不在jar包中,只要放在Class-Path下就行了,所以这种情况下,我更愿意把它称之为:读取Class-Path下的配置文件。而我今天描述的比较明确,就是要读取jar包中的文件。这种需求可能不多,但是我碰见了,并且发现了几种,今天全部罗列分享一下。

目前有3种:

  • JarFile
  • URL
  • ClassLoader

定义接口

因为有好几种方式,那就直接定义个接口:

public interface JarReader {
   /**
     * 读取jar包中的文件
     * @param jarPath   jar包路径
     * @param file  jar包中的文件路径
     * @return  文件内容,转换成字符串了,其它需求也可以转换成输入流。
     * @throws IOException
     */
    String readFromJar(String jarPath,String file) throws IOException;
}

jar包读取器,jar包中的文件读取出来。

通过JarFile读取

JarFile是java自带的一种读取jar包的API,很多人应该用过,我就直接贴代码了。public class JarFileJarReader implements JarReader {
    @Override
    public String readFromJar(String jarPath,String file) throws IOException {
        JarFile jarFile=null;
        try {
            jarFile=new JarFile(jarPath);
            JarEntry jarEntry=jarFile.getJarEntry(file);
            InputStream input=jarFile.getInputStream(jarEntry);
            return IOUtils.toString(input,"UTF-8");
        } catch (IOException e) {
            throw e;
        } finally {
            IOUtils.closeQuietly(jarFile);
        }
    }
}

代码也比较简单,重点就是最后一定要把jarFile这个对象关闭一下,中间的输入流都可以不用关闭。

不过我在写这段代码之前,从我的个人经验上来说,JarFile好像更多是用来读取清单文件(MANIFEST.MF)的,可能是见这种情况比较多,当然它的用途肯定远不止如此。
因此我顺便写了一下读取清单文件的代码:

public void getManiFest(String jarPath) throws IOException {
        JarFile jarFile=null;
        try {
            jarFile=new JarFile(jarPath);
            Manifest manifest=jarFile.getManifest();
            if (manifest!=null){
                //获取Class-Path
                String classPaths = (String) manifest.getMainAttributes().get(new Attributes.Name("Class-Path"));
                if (classPaths != null && !classPaths.isEmpty()) {
                    String[] classPathArray = classPaths.split(" ");
                }
                //获取JDK版本
                String jdkVersion = (String) manifest.getMainAttributes().get(new Attributes.Name("Build-Jdk"));
                //还可以获取其它内容,比如Main-Class等等
            }
        } catch (IOException e) {
            throw e;
        } finally {
            IOUtils.closeQuietly(jarFile);
        }
    }

通过URL读取

java自带的URL是支持读取jar中的文件的,协议是jar,表示方式的话是用"/!"把jar包和文件区分一下。代码如下:

public class URLJarReader implements JarReader {
    @Override
    public String readFromJar(String jarPath, String file) throws IOException {
        JarURLConnection jarURLConnection=null;
        try {
            URL fileUrl=ParseUtil.fileToEncodedURL(new File(jarPath));
            URL jarUrl=new URL("jar", "", -1, fileUrl + "!/");
            URL moduleUrl = new URL(jarUrl, ParseUtil.encodePath(file, false));
            jarURLConnection = (JarURLConnection)moduleUrl.openConnection();
            return IOUtils.toString(jarURLConnection.getInputStream(),"UTF-8");
        } catch (IOException e) {
            throw e;
        } finally {
            if (jarURLConnection!=null){
                try {
                    jarURLConnection.getJarFile().close();
                } catch (IOException ignore) {
                }
            }
        }
    }
}

ParseUtil的几个方法是我在看java源码的时候看见的,用来处理一些不规则的文件路径。

我刚开始用URL的时候,就出现了一个内存泄漏的文件,读取完了以后,jar包被占用,死活不能删除,刚才开始把输入流给关闭了,也没有用。然后想到了类加载器里面有close方法,然后去看了一下,找到了上述代码中的finally块的代码。这样就可以把占用问题解决了,仔细看的话,会发现,getJarFile.close(),因此本质上还是关闭了JarFile,和上面是一样的。

通过ClassLoader

这个也是借鉴了我们平时读取配置文件的方式,借用一下ClassLoader来读取。

public class ClassLoaderJarReader implements JarReader {
    @Override
    public String readFromJar(String jarPath, String file) throws IOException{
        URLClassLoader urlClassLoader=null;
        try {
            URL fileUrl=ParseUtil.fileToEncodedURL(new File(jarPath));
            urlClassLoader=new URLClassLoader(new URL[]{fileUrl},null);
            InputStream inputStream=urlClassLoader.getResourceAsStream(file);
            if (inputStream==null){
                throw new FileNotFoundException("not find file:"+file+" in jar:"+jarPath);
            }else{
                return IOUtils.toString(inputStream,"UTF-8");
            }
        } catch (IOException e) {
            throw e;
        } finally {
            IOUtils.closeQuietly(urlClassLoader);
        }
    }
}

代码也是比较简单,最后把ClassLoader关闭一下就行了。

关于类加载器的读取方式,我很早之前就看过了,它本质上用的就是上面两种方式结合起来读取文件的。

总结

这几种方式的话,其实没有什么区别,从开发角度来说的话,比较推荐第三种,因为是java自带的功能,也是比较完善,也简单,也不容易出错,而且它内部用的就是前面两种。不过从资源消耗上面来说,我猜测,前面两种应该占优,不过我也不纠结这个,没去研究。

有时候我们或许有另外一种需求,读取jar中的jar中的文件,这个在一些场景下,会使用到。最起码spring-boot确实是用到了,很早之前我看过它的实现,它就是把URL重写了一下,支持了一下多个"/!"表达式,就能够支持这种情况了。

到此这篇关于java实现读取jar包中配置文件的几种方式的文章就介绍到这了,更多相关java 读取jar包配置文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Aware源码设计示例解析

    Spring Aware源码设计示例解析

    这篇文章主要为大家介绍了Spring Aware源码设计示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • HttpMessageConverter报文信息转换器的深入讲解

    HttpMessageConverter报文信息转换器的深入讲解

    在Spring中内置了大量的HttpMessageConverter,通过请求头信息中的MIME类型,选择相应的HttpMessageConverter,这篇文章主要给大家介绍了关于HttpMessageConverter报文信息转换器的相关资料,需要的朋友可以参考下
    2022-01-01
  • Java线上问题排查过程

    Java线上问题排查过程

    本文详细介绍了如何通过命令行和可视化工具来诊断和解决CPU和内存使用率过高的问题,包括找到高占用率的进程和线程,分析堆内存使用情况,以及在内存溢出时自动保存堆快照文件的方法
    2026-03-03
  • Maven坐标和依赖的实现示例

    Maven坐标和依赖的实现示例

    本文主要介绍了Maven坐标和依赖的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-04-04
  • Maven学习教程之搭建多模块企业级项目

    Maven学习教程之搭建多模块企业级项目

    本篇文章主要介绍了Maven学习教程之搭建多模块企业级项目 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • java 流与 byte[] 的互转操作

    java 流与 byte[] 的互转操作

    这篇文章主要介绍了java 流与 byte[] 的互转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • Java算法之最长公共子序列问题(LCS)实例分析

    Java算法之最长公共子序列问题(LCS)实例分析

    这篇文章主要介绍了Java算法之最长公共子序列问题(LCS),结合实例形式分析了最长公共子序列的原理及问题解决方法,需要的朋友可以参考下
    2017-11-11
  • IKAnalyzer使用不同版本中文分词的切词方式实现相同功能效果

    IKAnalyzer使用不同版本中文分词的切词方式实现相同功能效果

    今天小编就为大家分享一篇关于IKAnalyzer使用不同版本中文分词的切词方式实现相同功能效果,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 通过实例解析spring对象生命周期

    通过实例解析spring对象生命周期

    这篇文章主要介绍了通过实例解析spring对象生命周期,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • 解决springboot接入springfox-swagger2遇到的一些问题

    解决springboot接入springfox-swagger2遇到的一些问题

    这篇文章主要介绍了解决springboot接入springfox-swagger2遇到的一些问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07

最新评论