Java 中的资源有多种,如File,URL, InputStream等,本篇将介绍在Java中获取classpath下的资源文件的几种方式。
一 Class.getResource
String name1 = "/prop/system.properties"; URL url1 = App.class.getResource(name1);
二 Class.getResourceAsStream
String name1 = "/prop/system.properties"; InputStream inputStream1 = App.class.getResourceAsStream(name1);
三 ClassLoader.getResource
String name2 = "prop/system.properties"; URL url2 = App.class.getClassLoader().getResource(name2);
四 ClassLoader.getResourceAsStream
String name2 = "prop/system.properties"; InputStream inputStream2 = App.class.getClassLoader().getResourceAsStream(name2);
五 ResourceBundle.getBundle
String name3 = "prop/system"; ResourceBundle resourceBundle = ResourceBundle.getBundle(name3);
注意资源名称不包含.properties
Class、ClassLoader获取资源文件区别
Class.getResource和Class.getResourceAsStream中,资源名称以"/"开头表示绝对定位,为类路径根目录下的资源文件, 否则资源名称被解析为以Class类的包名为父目录
ClassLoader.getResource和ClassLoader.getResourceAsStream中,资源名称不能以"/"开头,否则将找不到文件。
源码分析
Class类部分源码如下:
public final class Class<T> implements java.io.Serializable,GenericDeclaration,Type,AnnotatedElement { public java.net.URL getResource(String name) { name = resolveName(name); ClassLoader cl = getClassLoader0(); if (cl==null) { // A system class. return ClassLoader.getSystemResource(name); } return cl.getResource(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); } 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; } ClassLoader getClassLoader0() { return classLoader; } }
Class的getResource和getResourceAsStream首先调用resolveName方法解析资源名称,然后调用ClassLoader的getResource或getResourceAsStream方法;如果Class类中的域classLoader
为null还将调用ClassLoader.getSystemResource或ClassLoader.getSystemResourceAsStream方法获取系统资源。
Class的resolveName方法解析资源名称时对方法参数进行处理,如果以"/“开头则把开头的”/"截取,否则取包名为父目录和方法参数进行拼接。
ClassLoader部分源码如下:
public abstract class ClassLoader { 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; } public InputStream getResourceAsStream(String name) { URL url = getResource(name); try { return url != null ? url.openStream() : null; } catch (IOException e) { return null; } } }
ClassLoader的getResourceAsStream方法调用了getResource方法
ClassLoader的getResource方法首先尝试使用父类加载器获取资源,未获取到则调用findResource方法查找资源,findResource方法由子类覆盖。
总结
Class.getResource、 Class.getResourceAsStream、ClassLoader.getResourceAsStream最终都调用ClassLoader.getResource
如果将properties文件转换为java类Properties,可以使用ResourceBundle.getBundle方法。