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

物以类聚 人以群分
菅江晖

目录
相关文章
|
12天前
|
分布式计算 DataWorks Java
DataWorks操作报错合集之在使用MaxCompute的Java SDK创建函数时,出现找不到文件资源的情况,是BUG吗
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
26 0
|
15天前
|
安全 Java
【JAVA】在 Queue 中 poll()和 remove()有什么区别
【JAVA】在 Queue 中 poll()和 remove()有什么区别
|
15天前
|
Java API
【JAVA】final、finally、finalize 有什么区别?
【JAVA】final、finally、finalize 有什么区别?
|
15天前
|
Java
【JAVA】throw 和 throws 的区别?
【JAVA】throw 和 throws 的区别?
|
15天前
|
Java
【JAVA】Iterator 和 ListIterator 有什么区别?
【JAVA】Iterator 和 ListIterator 有什么区别?
|
1天前
|
Java
java一分钟之-字符流与字节流的区别
【5月更文挑战第11天】Java的输入输出通过流操作,分为字符流和字节流。字节流处理二进制数据,如图片、音频,基类是`InputStream`和`OutputStream`;字符流处理文本,基类是`Reader`和`Writer`。字符流涉及编码转换,字节流不涉及。易错点包括乱码(需指定编码)、混用流类型和忘记关闭流。示例展示了字节流和字符流读文件。理解区别并注意编码和资源管理可提高代码质量。
9 3
|
3天前
|
安全 Java 编译器
Java中String、StringBuilder和StringBuffer的区别
Java中String、StringBuilder和StringBuffer的区别
|
6天前
|
SQL Java 分布式数据库
实现HBase表和RDB表的转化(附Java源码资源)
该文介绍了如何将数据从RDB转换为HBase表,主要涉及三个来源:RDB Table、Client API和Files。文章重点讲解了RDB到HBase的转换,通过批处理思想,利用RDB接口批量导出数据并转化为`List<Put>`,然后导入HBase。目录结构包括配置文件、RDB接口及实现类、HBase接口及实现类,以及一个通用转换器接口和实现。代码中,`RDBImpl`负责从RDB读取数据并构造`Put`对象,`HBaseImpl`则负责将`Put`写入HBase表。整个过程通过配置文件`transfer.properties`管理HBase和RDB的映射关系。
22 3
实现HBase表和RDB表的转化(附Java源码资源)
|
10天前
|
Java
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
47 0
|
12天前
|
Java
Java中 a+=b和a=a+b有什么区别?
Java中 a+=b和a=a+b有什么区别?