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包配置文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis结果集映射与生命周期详细介绍

    Mybatis结果集映射与生命周期详细介绍

    结果集映射指的是将数据表中的字段与实体类中的属性关联起来,这样 MyBatis 就可以根据查询到的数据来填充实体对象的属性,帮助我们完成赋值操作
    2022-10-10
  • Java工厂模式之简单工厂,工厂方法,抽象工厂模式详解

    Java工厂模式之简单工厂,工厂方法,抽象工厂模式详解

    这篇文章主要为大家详细介绍了Java工厂模式之简单工厂、工厂方法、抽象工厂模式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • LinkedBlockingQueue链式阻塞队列的使用和原理解析

    LinkedBlockingQueue链式阻塞队列的使用和原理解析

    这篇文章主要介绍了LinkedBlockingQueue链式阻塞队列的使用和原理解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 详解Spring bean的注解注入之@Autowired的原理及使用

    详解Spring bean的注解注入之@Autowired的原理及使用

    之前讲过bean注入是什么,也使用了xml的配置文件进行bean注入,这也是Spring的最原始的注入方式(xml注入).本文主要讲解的注解有以下几个:@Autowired、 @Service、@Repository、@Controller 、@Component、@Bean、@Configuration、@Resource ,需要的朋友可以参考下
    2021-06-06
  • eclipse创建一个基于maven的web项目详细步骤

    eclipse创建一个基于maven的web项目详细步骤

    开始学习maven,并用maven创建了第一个属于自己的web项目,下面这篇文章主要给大家介绍了关于eclipse创建一个基于maven的web项目的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • Maven Pom 文件中的隐式依赖导致Jar冲突问题

    Maven Pom 文件中的隐式依赖导致Jar冲突问题

    这篇文章主要介绍了Maven Pom 文件中的隐式依赖导致Jar冲突问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • BufferedInputStream(缓冲输入流)详解_动力节点Java学院整理

    BufferedInputStream(缓冲输入流)详解_动力节点Java学院整理

    这篇文章主要为大家详细介绍了BufferedInputStream缓冲输入流的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • Java中 springcloud.openfeign应用案例解析

    Java中 springcloud.openfeign应用案例解析

    使用OpenFeign能让编写Web Service客户端更加简单,使用时只需定义服务接口,然后在上面添加注解,OpenFeign也支持可拔插式的编码和解码器,这篇文章主要介绍了Java中 springcloud.openfeign应用案例解析,需要的朋友可以参考下
    2024-06-06
  • Java高性能本地缓存框架Caffeine的实现

    Java高性能本地缓存框架Caffeine的实现

    本文主要介绍了Java高性能本地缓存框架Caffeine的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 一文详细讲解Java时间格式转换

    一文详细讲解Java时间格式转换

    这篇文章主要介绍了Java时间格式转换的相关资料,文中详细介绍了SimpleDateFormat(适用于Java8之前)和java.time(适用于Java8及之后)的用法,需要的朋友可以参考下
    2024-12-12

最新评论