如何优雅读取properties文件

Q:在java中如何加载properties文件或者configure文件才是最好的办法呢?

A:当你在考虑如何加载java的资源文件的时候,许多选择都会立即闪现在你的头脑中:files, classpath resources, 还有URLs。尽管上述所有的方法都能得到最终需要的效果,但经验表明classpath resources 和 URLs 是到目前为止最靠谱的选择。

通常情况下,一个配置文件都有一个异常复杂的结构(比如说xml结构的定义),为了简单,下文里我们以name-value对为例子来讲解(非 常类似properties文件的格式)。就算这样,只要你考虑使用inputStream来读取资源文件,你没有理由不采纳下文里提到的办法。

一、邪恶的java.io.File

任何没有java背景的人明显的做法是使用原来的files里的足够简单的办法(通过FileInputStream, FileReader,RandomAccessFile)。但是在java应用的布署来说,这是最差的办法。对于追求轻便和不依赖磁盘位置的代码来说, 在你的代码中使用绝对文件地址并不是一个很好的方式。使用相对路径看上去是个不错的替代方案,不过不要忘记,是相对于jvm运行时当前的路径。这个相对路 径的设置取决于JVM的启动进程,而且会被启动的shell等脚本搞混乱了。如果决定将一些不标准的设置存放依赖最终用户的环境(而且在一些情况下,还未 被验证过是否有用户权限),只要换个环境,(比如说EJB或者是WEB应用服务器),你和用户都不能有更多的基于JVM一开始启动时目录的控制。 java.io.File是java里最不能跨平台的部分。

java模块的做法是将其加入到classpath中去,直接就可用 。考虑EJB jars,Web应用可以打包成war文件,还有其他类似的便利的布署方式。除非你非得用它,还是对其说不吧。

二、Classpath resources

抛开上面所说的坏话,让我们来谈谈更好一点的办法:通过classloaders来加载资源。这样做会更好,因为classloaders本来就扮演了一个资源文件同它的在硬盘上或者其他地方实际位置的关系之间的抽象层。

比如说,你需要从some/pkg/resource.properties加载一个classpath的资源。使用classpath资源是指把文件打 包到jar包里或者是在程序运行前加入到classpath里。你可以通过JVM的参数-classpath在每次程序启动前向classpath中写 入,也可以一次性写到

\classes的位置一直使用。要点是classpath的资源文件布署和java class文件一样,而方便也正是在于此。

从java代码里拿some/pkg/resource.properties有许多方法。首先可以用:

<font face="Monaco" size="2">ClassLoader.getResourceAsStream (&quot;some/pkg/resource.properties&quot;);<br />Class.getResourceAsStream (&quot;/some/pkg/resource.properties&quot;);<br />ResourceBundle.getBundle (&quot;some.pkg.resource&quot;);</font>

此外,如果代码在一个位于some.pkg包的class里,下面的代码也可以很好地工作:

<font face="Monaco" size="2">Class.getResourceAsStream (&quot;resource.properties&quot;);<br /></font>

注意两者在参数上微妙的不同之处。所有的getResourceAsStream方法都使用斜杠分割包名的间隔,而且资源文件要包括扩展 名。和resource bundles相比,后者更像是java标识符,用点标识包(并且没有文件名后缀)。这是理所当然的,因为resource bundle(资源绑定)可以不仅仅是properties文件,比如还可以是class文件。

稍微有点复杂的地方,java.lang.Class的getResourceAsStream方法的实例方法可以执行相对于包的资源搜索 (同样也很灵活,见 http://www.javaworld.com/javaworld/javaqa/2002-11/02-qa-1122- resources.html)。为了区分相对和绝对的资源名字,Class.getResourceAsStream()用斜杠开头表示绝对路径。通 常,如果你在代码里不用相对于package的资源的话,没有必要使用这个方法。

ClassLoader.getResourceAsStream(), Class.getResourceAsStream(), ResourceBundle.getBundle()之间微小的区别很容易造成混乱。下面这个表记录了他们之间的特点:

方法操作差异

Method Parameter format Lookup failure behavior Usage example
ClassLoader.getResourceAsStream() “/”-separated names; no leading “/” (all names are absolute) Silent (returns null) this.getClass().getClassLoader()
.getResourceAsStream
(“some/pkg/resource.properties”)
Class.getResourceAsStream() “/”-separated names; leading “/” indicates absolute names; all other names are relative to the class’s package Silent (returns null) this.getClass()
.getResourceAsStream
(“resource.properties”)
ResourceBundle.getBundle() “.”-separated names; all names are absolute; .properties suffix is implied Throws unchecked
java.util.
MissingResource
Exception
ResourceBundle.getBundle(“some.pkg.resource”)

从数据流到java.util.Properties

你应该注意到之前提过的方法只是一半的措施:他们都只返回输入数据流,而并没有类似键值对的返回。幸运的是,把数据加载成一个列表很简单(可以实例化java.util.Properties即可)。因为你会发现你在一再地使用它,搞成几个帮助类是有意义的。

java的内置方法给classpath加载指定的资源有小小的不同也是一件讨厌的事情,特别是当一些资源名字是硬编码但你现在想换另一个加载 的方法时。抽取出来一些东西是有意义的,类似斜杠和点作为命名的分隔符等等。干脆一点,帖出我的properties的处理类,代码在这里下 载:http://www.javaworld.com/javaqa/2003-08/01-qa-0808- property.html?page=2#resources

[代码略]

在loadProperties方法的javadoc里的注释显示这个方法的输入参数要求非常随意:接受资源名字被任何按照原生的方法设计(除了相关的包外尽量使用Class.getResourceAsStream())的格式化而且使其本地实现标准化。

短一点的loadProperties() 公用方法决定了哪个类加载器加载资源。下面的解决方法是合理的但并非完美。你应该考虑使用文章” Find a Way Out of the ClassLoader Maze“里提到的技术来代替。

注意有两个条件编译的常量来控制loadProperties的行为,你可以调整它们来适应你的口味:

THROW_ON_LOAD_FAILURE选择loadProperties在找不到资源的情况下是抛异常还是返回空。

LOAD_AS_RESOURCE_BUNDLE 选择资源在查找的时候是绑定资源还是给出的classpath资源。

将LOAD_AS_RESOURCE_BUNDLE设置为true是不好的,除非你是想通过编译到java.util.ResourceBundle的本地化支持得到好处。而且,java内部缓存了资源绑定,所以你可以避免重复地对同样的资源名字进行磁盘文件读写。

更多的事情

我有意省略了一个有趣的classpath资源加载方法,ClassLoader.getResources。尽管它不常使用,但其允许许多有用的选项,这些选项在设计高度定制和简单配置的应用程序非常有用。

我没有在这文章里讨论ClassLoader.getResources是因为它值得专门写一篇文章。碰巧,这个方法与剩下的取得资源的方法联系紧密:Java.net.URLs。你可以使用他们,因为资源描述符要比classpath资源名字符要更通用。

时间: 2024-11-07 23:39:54

如何优雅读取properties文件的相关文章

五种方式让你在java中读取properties文件内容不再是难题

一.背景 最近,在项目开发的过程中,遇到需要在properties文件中定义一些自定义的变量,以供java程序动态的读取,修改变量,不再需要修改代码的问题.就借此机会把Spring+SpringMVC+Mybatis整合开发的项目中通过java程序读取properties文件内容的方式进行了梳理和分析,先和大家共享. 二.项目环境介绍 Spring 4.2.6.RELEASE SpringMvc 4.2.6.RELEASE Mybatis 3.2.8 Maven 3.3.9 Jdk 1.7 Id

在JSP页面中读取properties文件

在做web开发时,经常遇到要修改一下配置信息.如果把这些配置信息写在代码中,后期的维护便会比较麻烦.所以,一般都是把配置信息写在配置文件里面. 在JSP文件中,如果想要调用properties文件中的变量,则要在有文件中引入 java.util.ResourceBundle 类: <%@ page contentType="text/html; charset=UTF-8" import="java.util.ResourceBundle" %> 已知配

Java读取Properties文件的六种方法

使用J2SE API读取Properties文件的六种方法 1.使用java.util.Properties类的load()方法 示例: InputStream in = lnew BufferedInputStream(new FileInputStream(name)); Properties p = new Properties(); p.load(in); 2.使用java.util.ResourceBundle类的getBundle()方法 示例: ResourceBundle rb

转载:java基础学习总结——java读取properties文件总结

java基础学习总结--java读取properties文件总结 一.java读取properties文件总结 在java项目中,操作properties文件是经常要做的,因为很多的配置信息都会写在properties文件中,这里主要是总结使用getResourceAsStream方法和InputStream流去读取properties文件,使用getResourceAsStream方法去读取properties文件时需要特别注意properties文件路径的写法,测试项目如下: 1.1.项目的

Java读取.properties文件

例1: 创建一个config文件夹 config文件夹中有一个Properties.properties文件 内容为: capitalLetter=ABCDE smallLetter=abcde 注意:config文件夹与包含Test类的包为同一级 import java.io.IOException; import java.util.Properties; public class Test { public static void main(String[] args) { Propert

java读取.properties文件及解决中文乱码问题

Java项目中有些信息(例如web的配置信息)可能要放在.properties文件中,那我们应该怎么来读取它们呢,下面给出一个工具类做一说明,并解决了中文乱码问题: 1.其中config.properties文件信息如下: name=\u843D\u82B1\u6709\u610Fwang王 str=\u6D41\u6C34\u65E0\u60C5 boolean=true 2.PropertiesUtil工具类读取.properties文件 import java.io.BufferedInp

用java读取properties文件--转

今天为了通过java读取properties文件,google了很长时间,终于找到了.现在特记录之和大家一起分享.     下面直接贴出代码:java类 public class Mytest public static void readFile(String fileName) {//传入参数fileName是要读取的资源文件的文件名如(file.properties) InputStream in = null; Properties pros = new Properties(); tr

Java实现动态加载读取properties文件

问题: 当我们使用如下语句加载.properties时: ClassLoader classLoader = this.getClass().getClassLoader(); Properties prop = new Properties(); prop.load(classLoader.getResourceAsStream("/Application.properties")); 会发现修改了.properties后,即使重新执行,读入的仍为修改前的参数.此问题的原因在于Cla

读取Properties文件以及中文乱码问题

在java类中常见的读取Properties文件方式,是使用Properties.load(inputStream);的方式但是常常出现中文乱码问题,这就很尴尬了 public synchronized void load(InputStream inStream) throws IOException { load0(new LineReader(inStream)); } 看了很久才发现,还有一个重载的方法, 它的参数是Reader,如下: public synchronized void