Java获取外部资源文件的几种方式和区别

简介: Java有很多获取外部资源的方式。本篇文章将使用流(Stream)的方式为大家演示&排惑!

获取外部资源的几种方式

1.使用FileInputStream(不推荐)


使用FileInputStream要传入File对象,此处便于演示,将输出配置文件的位置。
代码
   InputStream is = new FileInputStream(new File("ReflectDemo/resource/pro.properties"));
   System.out.println(new File("ReflectDemo/resource/pro.properties").getPath());
结果
ReflectDemo\resource\pro.properties
注:使用此方法获取获取配置文件要指定文件的绝对路径/相对路径。并且获取到的是在项目根目录下盘符下的配置文件,对于出现在classpath(类路径)下的配置文件,FileInputStream是读不到的。

2.使用Class.getResourceAsStream()方法


此处便于演示,将调用Class.Resource().getPath()来输出文件位置
代码
System.out.println(ReflectDemo.class.getResource("/pro.properties").getPath());
结果
/D:/idea/object/out/production/ReflectDemo/pro.properties

此方法可以用于获取类路径的配置文件。

3.Class.getClassLoder().getResourceAsStream()方法


此处便于演示,将调用Class.getClassLoder().Resource().getPath()来输出文件位置
代码
System.out.println(ReflectDemo.class.getClassLoader().getResource("pro.properties").getPath());
结果
/D:/idea/object/out/production/ReflectDemo/pro.properties

以上两方法区别
Class.getResourceAsStream(String name) 其实调用的就是
Class.getClassLoder().getResourceAsStream(String name)。

     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);
    }
调用之前多了一个用于解析name的操作,如果开头是“/”则跟直接调用Class.getClassLoder().getResourceAsStream(String path)一样
例:Class.getClassLoder().getResourceAsStream("");==Class.getResourceAsStream("/");
如果Class.getResourceAsStream(String name);开头不是"/",则Class.resolveName(name)方法将会返回此类文件的目录+name
也就是说此方法获取的Resource是在此类目录下的并非classpath根目录
他们最终都会调用ClassLoder.getResource(String name);
这个方法通过递归实现,双亲委派原理。
源代码

   /**
     * ...
     * @param  name
     *         The resource name
     *
     * @return  A URL object for reading the resource, or
     *          null if the resource could not be found or the invoker
     *          doesn't have adequate  privileges to get the resource.
     *
     * @since  1.1
    **/
    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;
    }

"该方法将首先在父类加载器中搜索资源; 如果父类加载器为null,则搜索虚拟机内置的类加载器的路径。 那个方法失败,将调用findResource(String)来查找资源。"

简单的说 就是第一次执行进去首先迭代进入最顶层的启动类加载器(Bootstrap ClassLoader)如果找不到资源,就会返回null ,并跳出去执行它子加载器(Extension ClassLoader)重写的findResource方法,如果返回null就继续跳出执行下一个子加载器(App ClassLoader)的findResoure方法,如果继续返回空的话(在没有自定义类加载器的情况下,就会直接返回 null。有的话,继续执行自定义类加载器的findResource方法)。这个方法会返回resource的URL对象 或者 nul。

对于喜欢"钻牛角尖"的小白,可能对于上面出现的 双亲委派Bootstrap ClassLoaderExtension ClassLoaderApp ClassLoader术语很困扰。请点击链接进行详细了解。

4.ClassLoader.getSystemResource()方法


相信眼睛尖的小伙伴已经发现了Class.getResourceAsStream()源代码中出现了这个方法。其实正如此方法所言,就是通过调用系统类加载器(App ClassLoader)的getResource()方法,和前两种方法没有什么本质上的区别。

总结

1.一般不推荐通过FileInputStream 来获取资源文件
1.现在的web项目,resources编译后就在classes目录下,通过classloader可以直接获取
2.对于变动的环境(现在都是部署在linux机器上)来说不太适用。
2.class.getResource("/") == class.getClassLoader().getResource("")
其实,Class.getResource和ClassLoader.getResource本质上是一样的,都是使用ClassLoader.getResource加载资源的。
3.Class.getResource真正调用ClassLoader.getResource方法之前,会先获取文件的路径(path不以'/'开头时,默认是从此类所在的包下取资源;path以'/'开头时,则是从项目的ClassPath根下获取资源)。
4.ClassLoader.getResource方法会通过双亲委派机制,先委派双亲去加载类,如果双亲没有加载到,则再由自己加载。

参考链接&进一步阅读

https://blog.csdn.net/zhangshk_/article/details/82704010
https://blog.csdn.net/eff666/article/details/52203406

物以类聚 人以群分
菅江晖

目录
相关文章
|
26天前
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
49 9
|
1月前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
59 2
|
5天前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
|
16天前
|
Java Maven Spring
Java Web 应用中,资源文件的位置和加载方式
在Java Web应用中,资源文件如配置文件、静态文件等通常放置在特定目录下,如WEB-INF或classes。通过类加载器或Servlet上下文路径可实现资源的加载与访问。正确管理资源位置与加载方式对应用的稳定性和可维护性至关重要。
|
26天前
|
Java 开发者
JAVA高手必备:URL与URLConnection,解锁网络资源的终极秘籍!
在Java网络编程中,URL和URLConnection是两大关键技术,能够帮助开发者轻松处理网络资源。本文通过两个案例,深入解析了如何使用URL和URLConnection从网站抓取数据和发送POST请求上传数据,助力你成为真正的JAVA高手。
47 11
|
22天前
|
Java
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别
|
30天前
|
Java
通过Java代码解释成员变量(实例变量)和局部变量的区别
本文通过一个Java示例,详细解释了成员变量(实例变量)和局部变量的区别。成员变量属于类的一部分,每个对象有独立的副本;局部变量则在方法或代码块内部声明,作用范围仅限于此。示例代码展示了如何在类中声明和使用这两种变量。
|
2月前
|
Java
java基础(4)public class 和class的区别及注意事项
本文讲解了Java中`public class`与`class`的区别和注意事项。一个Java源文件中只能有一个`public class`,并且`public class`的类名必须与文件名相同。此外,可以有多个非`public`类。每个类都可以包含一个`main`方法,作为程序的入口点。文章还强调了编译Java文件生成`.class`文件的过程,以及如何使用`java`命令运行编译后的类。
43 3
java基础(4)public class 和class的区别及注意事项
|
1月前
|
Java
Java基础之 JDK8 HashMap 源码分析(中间写出与JDK7的区别)
这篇文章详细分析了Java中HashMap的源码,包括JDK8与JDK7的区别、构造函数、put和get方法的实现,以及位运算法的应用,并讨论了JDK8中的优化,如链表转红黑树的阈值和扩容机制。
27 1
|
1月前
|
Java 编译器 C语言
【一步一步了解Java系列】:探索Java基本类型与C语言的区别
【一步一步了解Java系列】:探索Java基本类型与C语言的区别
45 2
下一篇
无影云桌面