项目中不同位置资源文件读取的几种方式

简介: 项目中不同位置资源文件读取的几种方式

项目工程下读取文件的几种方式。

【1】图片在src目录下,即资源文件;

此时测试类与图片位置无关

//使用getClassLoader,不加 `/`
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("getTclazz.jpg");
//这里需要加 `/`  
InputStream inputStream = getClass().getResourceAsStream("/getTclazz.jpg");


【2】图片在dao目录下

① 如果测试类不在该目录下-与文件不同目录

项目完整路径:

 /*不要加 `/` , /com/jdbc/dao/getTclazz.jpg 错误!   */
 InputStream inputStream = 
 getClass().getClassLoader().getResourceAsStream("com/jdbc/dao/getTclazz.jpg");
// 要加 `/`
InputStream inputStream = getClass().getResourceAsStream("/com/jdbc/dao/getTclazz.jpg");



② 如果测试类在该目录下-与文件同一目录

调用的java类文件在该包下,【如测试类和文件都在com.jdbc.dao包下】则可使用:
InputStream inputStream = getClass().getResourceAsStream("getTclazz.jpg");


分析:这里没有加包名也没有加"/" 。这是因为InputStream java.lang.Class.getResourceAsStream(String name)会根据name解析具体资源路径。


【3】三种方式分析

上面总结实例了三种方式,如下所示:



getClass().getResourceAsStream(“getTclazz.jpg”);


getClass().getResourceAsStream("/com/jdbc/dao/getTclazz.jpg");**


getClass().getClassLoader().getResourceAsStream(“com/jdbc/dao/getTclazz.jpg”);**


第一种和第二种方式是采用Class对象去加载,第三种采用ClassLoader对象去加载资源文件,之所以Class对象也可以加载资源文件是因为InputStream java.lang.Class.getResourceAsStream(String name) 方法最终会调用InputStream java.lang.ClassLoader.getResourceAsStream(String name) 方法。通常我们的类加载器会使用sun.misc.Launcher$AppClassLoader这个类加载器。Class类中的源码getResourceAsStream

public InputStream getResourceAsStream(String name) {
  //这里有名字解析操作
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResourceAsStream(name);
        }
        return cl.getResourceAsStream(name);
    }


分析如下:


使用给定的名字找到一个资源,检索资源的规则与当前类的类加载器ClassLoader有关。如果当前对象是被根加载器加载的,那么将会直接调用ClassLoader.getSystemResourceAsStream(name)方法。但是在判断使用哪个类加载器获取资源前,需要根据算法来构造一个绝对路径名字:


如果name是以/开头,那么绝对资源路径名字就是 / 后面的部分;

否则绝对路径名字就是当前类的包名+/+name;其中包名里面的. 被/替换。

注意,上面第二句里面有个当前类,其实就是你调用代码获取资源的那个类。String java.lang.Class.resolveName(String name)方法源码如下:

    private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {
            Class<?> c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            //这里将会获取当前测试类的包名,并将 `.` 替换为 `/`  
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }
        } else {
            name = name.substring(1);
        }
        return name;
    }


即,如果name是绝对路径(带有/)那么就移除/然后使用classloader.getResourceAsStream(name)来获取流。如果name是相对路径(不带有/),那么就添加包前缀,然后使用classloader.getResourceAsStream(name)来获取流。

InputStream java.lang.ClassLoader.getResourceAsStream(String name)方法如下:

//不会再次解析name
public InputStream getResourceAsStream(String name) {
        URL url = getResource(name);
        try {
            return url != null ? url.openStream() : null;
        } catch (IOException e) {
            return null;
        }
    }


最终获取资源方法URL java.lang.ClassLoader.getResource(String name)

public URL getResource(String name) {
        URL url;
        if (parent != null) {
            url = parent.getResource(name);
        } else {
         // 使用该方法加载资源
            url = getBootstrapResource(name);
        }
        if (url == null) {
            url = findResource(name);
        }
        return url;
}

分析如下:


首先查看当前类加载的父类加载器是否存在,如果存在则调用父类加载器的getResource方法;

如果父类加载不存在则使用根类加载器加载资源;

如果url还是为null,则使用当前类加载查找资源;

看会是不是觉得就是双亲委派?联想下类的加载过程。如果对类加载不熟悉可以参考该篇博文: 细究Java类加载机制和Tomcat类加载机制

————————————————

【4】Debug分析资源在src根目录下的检索过程

资源图示如下:

实例代码

InputStream fis = EmailConfig.class.getResourceAsStream("/email.properties");



20191031142216877.png


① 调用Class的getResourceAsStream方法,此时name为/email.properties

② 解析name并获取类加载器

解析到的name为email.properties,类加载器为sun.misc.Launcher$AppClassLoader@18b4aac2


③ 调用URL java.lang.ClassLoader.getResource(String name)开始查找资源



当前类加载器为AppClassLoader,其父类加载器为ExtClassLoader,不为null则调用其父类加载器查找资源。


当前类加载器为ExtClassLoader,其父类加载器为null,则调用根加载器查找资源。


根加载器当然拿不到了,那么就返回当前类加载器ExtClassLoader并调用URL java.net.URLClassLoader.findResource(String name)进行资源查找。



那么会从哪些地方进行查找呢?这里整理如下(也就是/jre/lib/ext下):

[
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/access-bridge-64.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/cldrdata.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/dnsns.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/jaccess.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/jfxrt.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/localedata.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/nashorn.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/sunec.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/sunjce_provider.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/sunmscapi.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/sunpkcs11.jar,
    file: /C: /Program%20Files/Java/jdk1.8.0_101/jre/lib/ext/zipfs.jar
]


此时资源仍旧拿不到!这是正常的,继续往上返回,返回到AppClassLoader。再次调用URLClassLoader进行资源查找:



路径整理如下(tomcat/lib目录下以及项目资源目录下):

[
    file: /C: /Users/jane/workspace2/JavaMailDemo/build/classes/,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/annotations-api.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/catalina-ant.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/catalina-ha.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/catalina-storeconfig.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/catalina-tribes.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/catalina.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/ecj-4.6.3.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/el-api.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/jasper-el.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/jasper.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/jaspic-api.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/jsp-api.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/servlet-api.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-api.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-coyote.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-dbcp.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-i18n-es.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-i18n-fr.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-i18n-ja.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-i18n-ru.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-jdbc.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-jni.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-util-scan.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-util.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/tomcat-websocket.jar,
    file: /E: /softinstall/tomcat8.5/apache-tomcat-8.5.38/lib/websocket-api.jar,
    file: /C: /Users/jane/workspace2/JavaMailDemo/WebContent/WEB-INF/lib/javax.mail-api-1.4.4.jar,
    file: /C: /Users/jane/workspace2/JavaMailDemo/WebContent/WEB-INF/lib/slf4j-api-1.7.26.jar
]


此时就获取到了资源!


【5】读取classpath下的json文件并返回JSONObject

这里使用的是fastJSON,源码实例如下:

  /**
     * 读取json文件并解析为JSONObject
     * @param path--文件保存在classpath下的全路径 如test.json
     */
    public static JSONObject readerJSON (String path) throws Exception {
        try {
            if (!path.startsWith("/")&&!path.startsWith("\\")){
                path="/"+path;
            }
            InputStream inputStream = ReaderJSONUtil.class.getResourceAsStream(path);
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            StringBuffer jsonBuffer = new StringBuffer();
            String line=null;
            while ((line=bufferedReader.readLine())!=null){
                jsonBuffer.append(line);
                log.debug(line);
            }
            return JSON.parseObject(jsonBuffer.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


目录
相关文章
|
SQL 缓存 算法
CPU密集型和IO密集型任务的权衡:如何找到最佳平衡点
CPU密集型与I/O密集型是在计算机上执行任务的两种策略,在并发执行任务场景下,我们需要选择使用多线程或多进程; 如果是IO密集型任务,使用多线程,线程越多越好; 如果是CPU密集型任务,使用多进程,线程数量与CPU核心数匹配。
1728 0
|
3月前
|
存储 Java PHP
轻量化短视频电商直播带货APP源码全解析:核心功能与设计流程​
在电商直播热潮下,开发专属直播带货APP成为抢占市场关键。本文详解原生开发轻量化APP的核心功能与全流程设计,涵盖用户登录、商品浏览、直播互动、购物车、订单及售后功能,并介绍安卓端Java、苹果端Object-C、后台PHP的技术实现,助力打造高效优质的直播电商平台。
|
8月前
|
机器学习/深度学习 设计模式 API
Python 高级编程与实战:构建微服务架构
本文深入探讨了 Python 中的微服务架构,介绍了 Flask、FastAPI 和 Nameko 三个常用框架,并通过实战项目帮助读者掌握这些技术。每个框架都提供了构建微服务的示例代码,包括简单的 API 接口实现。通过学习本文,读者将能够使用 Python 构建高效、独立的微服务。
|
12月前
|
机器学习/深度学习 数据可视化 算法
机器学习中的特征选择与降维技术
机器学习中的特征选择与降维技术
406 0
|
机器学习/深度学习 数据采集 人工智能
探索机器学习中的特征工程最佳实践
【5月更文挑战第21天】 在机器学习领域,特征工程是模型性能优化的关键环节之一。本文将深入探讨特征工程的核心概念、方法及其在构建高效机器学习模型中的应用。文章不仅总结了实用的特征选择技巧和数据预处理策略,还介绍了如何通过自动化工具简化特征工程流程。通过案例分析,我们展示了在不同数据集上应用这些技术的效果,并讨论了特征工程在未来发展中的潜在趋势与挑战。
|
存储 设计模式 安全
Java GenericObjectPool 对象池化技术--SpringBoot sftp 连接池工具类
Java GenericObjectPool 对象池化技术--SpringBoot sftp 连接池工具类
408 0
|
SQL 数据可视化 关系型数据库
快速导入mysql较大的SQL文件
快速导入mysql较大的SQL文件
819 0
|
Cloud Native Java Go
Springboot 获取 /resources 目录资源文件的 9 种方法
Springboot 获取 /resources 目录资源文件的 9 种方法
3551 0
|
监控 安全 Java
Spring Boot优雅Shutdown时异步线程安全优化
Spring Boot优雅Shutdown时异步线程安全优化
|
XML Java 数据格式
SpringBoot配置文件 | 多环境配置 | 读取配置的4种方式
SpringBoot配置文件 | 多环境配置 | 读取配置的4种方式