以下实践的是Properties配置文件的基本操作方法。像spring使用xml做依赖注入时,这个配置文件起到非常实用的作用。

一、格式规范

参考wiki百科的格式简介:https://zh.wikipedia.org/wiki/.properties,说明如下:

每个.properties 文件中的行通常存储单个属性。对于每一行可能有这么几种格式,包括键=值,键 = 值,键:值,以及键 值。
.properties文件可以使用井号(#)或叹号(!)作为一行中第一个非空白字符来表示它后面的所有文本都是一个注释。反斜杠(\)用于转义字符。

提供的示例如下:

# You are reading the ".properties" entry.
! The exclamation mark can also mark text as comments.
# The key and element characters #, !, =, and : are written with
# a preceding backslash to ensure that they are properly loaded.
website = http\://en.wikipedia.org/
language = English
# The backslash below tells the application to continue reading
# the value onto the next line.
message = Welcome to \
          Wikipedia\!
# Add spaces to the key
key\ with\ spaces = This is the value that could be looked up with the key "key with spaces".
# Unicode
tab : \u0009\u4E2D\u6587

接下来在eclipse测试可行性。使用最简单的代码:

Properties prop = new Properties();
        try {
            prop.load(Main.class.getResourceAsStream("test.properties"));
            for (Object key : prop.keySet()) { 
                System.out.println(key + "=" + prop.get(key)); 
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

正常输出,没任何报错,结果如下:

Properties解析中文一堆问号 properties文件转义字符_System

所以,参照wiki百科的写法是完全兼容的。但是有一点需要注意的:为了避免读取简单易懂,最好不要换行;和中文会转换成Unicode,当要写中文时,建议用英文或者拼音代替。 

提示:很多专业的写法会分模块写,比如Test.ProjectName=Test;这样也是完全兼容的。

二、存放位置及读取

注意:非必要的时候不要使用绝对路径,除非非常确定配置文件的位置。

读取的重点在于路径,路径之后就是获取文件流。参考此处进行文件路径的获取:,实质上除了路径获取外其它方法有提供流的获取。

application:

1、存放:在jar包中其实任何位置都可以放,因为最终都会按照开发工程的目录结构复制到jar包中,只要获取的方式对就可以了。比如放在src外面,src里面的特定包中,METE-INF文件夹内部等都可以。但是不要放在项目的根目录,因为默认打jar包是不会复制进去的。

存放位置参考:

Properties解析中文一堆问号 properties文件转义字符_jar包_02

最终默认打application包时的目录如下:

Properties解析中文一堆问号 properties文件转义字符_System_03

但是如果要把test3.properties文件打包进jar包时,可以手动Export导出jar包,包含进去:

Properties解析中文一堆问号 properties文件转义字符_java_04

最终得到如下jar包目录:

Properties解析中文一堆问号 properties文件转义字符_jar包_05

但是非常不建议这么做,主要有如下几点问题存在:

①如果使用File对象(#autoid-0-1-0第二点)读取文件时,指向的目录是工作目录;如果是eclipse运行时,指向的是eclipse的工作目录;而用jar包运行时,指向的就是jar包所在的目录;那么也就是说读取的不是jar包内的文件,而是外部的文件;所以用File对象去读取的方法在jar包上不可取。

②如果使用Class.class.getResource这类方法(#autoid-0-2-0第三点)获取的路径,在eclipse上获取是编译后class目录,而这个目录默认只会复制src/appClientModule目录下的文件,在项目根目录下的文件是不会复制过去的,所以在eclipse上无法获取到;但是通过后期打包加入test3.properties时,在jar包上本身和class同一级目录,所以此时可以正常读取。这样一来也就是和调试时都不能同步,所以这里不建议放在根目录。

2、读取:参考:

以下为用File对象和类方法获取以上目录结构文件的方法:

①File对象(不建议使用):

参考:#autoid-0-1-0(第二中方法)

java.util.Properties类的load方法传入的参数为InputStream,所以只要根据File对象构建出来即可,代码如下:

new BufferedInputStream(new FileInputStream(new File("test3.properties")));  
new BufferedInputStream(new FileInputStream(new File("appClientModule/test.properties")));  
new BufferedInputStream(new FileInputStream(new File("appClientModule/META-INF/test2.properties")));  
new BufferedInputStream(new FileInputStream(new File("appClientModule/properties/test/test1.properties")));

②类方法获取(推荐使用):

类方法获取有很多种,参考:#autoid-0-2-0(第三种方法)

但是,用类方法获取test3.properties文件就无法在elipse中获取。所以下面代码将省略,代码如下:

Main.class.getResourceAsStream("/test.properties");  
Main.class.getResourceAsStream("/properties/test/test1.properties");  
Main.class.getResourceAsStream("/META-INF/test2.properties");

Main.class.getClassLoader().getResourceAsStream("test.properties");  
Main.class.getClassLoader().getResourceAsStream("properties/test/test1.properties");  
Main.class.getClassLoader().getResourceAsStream("META-INF/test2.properties");  

Thread.currentThread().getContextClassLoader().getResourceAsStream("test.properties");  
Thread.currentThread().getContextClassLoader().getResourceAsStream("properties/test/test1.properties");  
Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/test2.properties");

ClassLoader.getSystemClassLoader().getResourceAsStream("test.properties");  
ClassLoader.getSystemClassLoader().getResourceAsStream("properties/test/test1.properties");  
ClassLoader.getSystemClassLoader().getResourceAsStream("META-INF/test2.properties");

注意:上面开头的斜杠写法,以及包的路径写法。

经过测试上面路径在jar上正常运行:

Properties解析中文一堆问号 properties文件转义字符_System_06

下面开始测试各个类库对properties文件的读取:

注意:由于File对象的局限性,所以不作为测试。

① 使用java.util.Properties类的load(InputStream in)方法加载properties文件:

Properties prop2 = new Properties();    
prop2.load(Main.class.getResourceAsStream("/test.properties"));  
System.out.println(prop2.getProperty("message"));  
prop2.load(Main.class.getResourceAsStream("/properties/test/test1.properties"));  
System.out.println(prop2.getProperty("message")); 
prop2.load(Main.class.getResourceAsStream("/META-INF/test2.properties"));  
System.out.println(prop2.getProperty("message")); 

System.out.println(""); 

Properties prop3 = new Properties();    
prop3.load(Main.class.getClassLoader().getResourceAsStream("test.properties"));  
System.out.println(prop3.getProperty("message"));  
prop3.load(Main.class.getClassLoader().getResourceAsStream("properties/test/test1.properties"));  
System.out.println(prop3.getProperty("message")); 
prop3.load(Main.class.getClassLoader().getResourceAsStream("META-INF/test2.properties"));  
System.out.println(prop3.getProperty("message")); 

System.out.println(""); 

Properties prop4 = new Properties();    
prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("test.properties"));  
System.out.println(prop4.getProperty("message"));  
prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("properties/test/test1.properties"));  
System.out.println(prop4.getProperty("message")); 
prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/test2.properties"));  
System.out.println(prop4.getProperty("message")); 

System.out.println(""); 

Properties prop5 = new Properties();    
prop5.load(ClassLoader.getSystemClassLoader().getResourceAsStream("test.properties"));  
System.out.println(prop5.getProperty("message"));  
prop5.load(ClassLoader.getSystemClassLoader().getResourceAsStream("properties/test/test1.properties"));  
System.out.println(prop5.getProperty("message")); 
prop5.load(ClassLoader.getSystemClassLoader().getResourceAsStream("META-INF/test2.properties"));  
System.out.println(prop5.getProperty("message"));

eclipse输出结果:

Properties解析中文一堆问号 properties文件转义字符_System_07

jar输出结果:

Properties解析中文一堆问号 properties文件转义字符_jar包_08

测试一切正常。

②使用java.util.ResourceBundle类的getBundle()方法:

注意:这个getBundle()方法的参数只能写成包路径+properties文件名,也就说不用带文件的后缀。

System.out.println(ResourceBundle.getBundle("test").getString("message"));
System.out.println(ResourceBundle.getBundle("properties/test/test1").getString("message"));
System.out.println(ResourceBundle.getBundle("META-INF/test2").getString("message"));

eclipse输出结果:

Properties解析中文一堆问号 properties文件转义字符_Properties解析中文一堆问号_09

jar输出结果:

Properties解析中文一堆问号 properties文件转义字符_System_10

测试一切正常。

③使用java.util.PropertyResourceBundle类的构造函数:

System.out.println(new PropertyResourceBundle(Main.class.getResourceAsStream("/test.properties")).getString("message"));  
System.out.println(new PropertyResourceBundle(Main.class.getResourceAsStream("/properties/test/test1.properties")).getString("message"));  
System.out.println(new PropertyResourceBundle(Main.class.getResourceAsStream("/META-INF/test2.properties")).getString("message"));

System.out.println(""); 

System.out.println(new PropertyResourceBundle(Main.class.getClassLoader().getResourceAsStream("test.properties")).getString("message"));  
System.out.println(new PropertyResourceBundle(Main.class.getClassLoader().getResourceAsStream("properties/test/test1.properties")).getString("message"));  
System.out.println(new PropertyResourceBundle(Main.class.getClassLoader().getResourceAsStream("META-INF/test2.properties")).getString("message"));  

System.out.println(""); 

System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("test.properties")).getString("message"));  
System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("properties/test/test1.properties")).getString("message"));  
System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/test2.properties")).getString("message"));

System.out.println(""); 

System.out.println(new PropertyResourceBundle(ClassLoader.getSystemClassLoader().getResourceAsStream("test.properties")).getString("message"));  
System.out.println(new PropertyResourceBundle(ClassLoader.getSystemClassLoader().getResourceAsStream("properties/test/test1.properties")).getString("message"));  
System.out.println(new PropertyResourceBundle(ClassLoader.getSystemClassLoader().getResourceAsStream("META-INF/test2.properties")).getString("message"));

eclipse输出结果:

Properties解析中文一堆问号 properties文件转义字符_java_11

jar输出结果:

Properties解析中文一堆问号 properties文件转义字符_Properties解析中文一堆问号_12

测试一切正常。

测试工程:https://github.com/easonjim/5_java_example/tree/master/propertiestest/application

 

Web:

1、存放:

基本都是任意位置,但是不能放在项目根目录,如下图所示参考:

Properties解析中文一堆问号 properties文件转义字符_开发工具_13

对于最优的放置位置,参考:http://stackoverflow.com/questions/2161054/where-to-place-and-how-to-read-configuration-resource-files-in-servlet-based-app,说:如果propertiesfile是webapp特定的,最好是放置它/WEB-INF/classes。如果您在IDE中开发标准WAR项目,请将其放在src文件夹(项目的源文件夹)中。如果你使用Maven项目,将其放在/main/resources文件夹中。

2、读取:

①使用java.util.Properties类的load(InputStream in)方法加载properties文件:

Properties prop2 = new Properties();   
        prop2.load(Index.class.getResourceAsStream("/test4.properties"));  
        System.out.println(prop2.getProperty("message"));  
        prop2.load(Index.class.getResourceAsStream("/properties/test/test5.properties"));  
        System.out.println(prop2.getProperty("message")); 
        prop2.load(Index.class.getResourceAsStream("/webtest/test7.properties"));  
        System.out.println(prop2.getProperty("message"));          
        //以下为servlet独有
        prop2.load(request.getSession().getServletContext().getResourceAsStream("/META-INF/test3.properties"));  
        System.out.println(prop2.getProperty("message")); 
        prop2.load(request.getSession().getServletContext().getResourceAsStream("/WEB-INF/lib/test6.properties"));  
        System.out.println(prop2.getProperty("message")); 
        prop2.load(request.getSession().getServletContext().getResourceAsStream("/WEB-INF/test2.properties"));  
        System.out.println(prop2.getProperty("message")); 
        prop2.load(request.getSession().getServletContext().getResourceAsStream("/test1.properties"));  
        System.out.println(prop2.getProperty("message")); 

        System.out.println(""); 

        Properties prop3 = new Properties(); 
        prop3.load(Index.class.getClassLoader().getResourceAsStream("test4.properties"));  
        System.out.println(prop3.getProperty("message"));  
        prop3.load(Index.class.getClassLoader().getResourceAsStream("properties/test/test5.properties"));  
        System.out.println(prop3.getProperty("message")); 
        prop3.load(Index.class.getClassLoader().getResourceAsStream("webtest/test7.properties"));  
        System.out.println(prop3.getProperty("message")); 
        prop3.load(Index.class.getClassLoader().getResourceAsStream("../../META-INF/test3.properties"));  
        System.out.println(prop3.getProperty("message"));  
        prop3.load(Index.class.getClassLoader().getResourceAsStream("../lib/test6.properties"));  
        System.out.println(prop3.getProperty("message")); 
        prop3.load(Index.class.getClassLoader().getResourceAsStream("../test2.properties"));  
        System.out.println(prop3.getProperty("message")); 
        prop3.load(Index.class.getClassLoader().getResourceAsStream("../../test1.properties"));  
        System.out.println(prop3.getProperty("message")); 
        
        System.out.println(""); 

        Properties prop4 = new Properties();    
        prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("test4.properties"));  
        System.out.println(prop4.getProperty("message"));  
        prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("properties/test/test5.properties"));  
        System.out.println(prop4.getProperty("message")); 
        prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("webtest/test7.properties"));  
        System.out.println(prop4.getProperty("message")); 
        prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("../../META-INF/test3.properties"));  
        System.out.println(prop4.getProperty("message"));  
        prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("../lib/test6.properties"));  
        System.out.println(prop4.getProperty("message")); 
        prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("../test2.properties"));  
        System.out.println(prop4.getProperty("message")); 
        prop4.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("../../test1.properties"));  
        System.out.println(prop4.getProperty("message")); 

        System.out.println(""); 
        
        //ClassLoader.getSystemClassLoader().getResourceAsStream()在web中不可用
        /*Properties prop5 = new Properties();    
        prop5.load(ClassLoader.getSystemClassLoader().getResourceAsStream("test4.properties"));  
        System.out.println(prop5.getProperty("message"));  
        prop5.load(ClassLoader.getSystemClassLoader().getResourceAsStream("properties/test/test5.properties"));  
        System.out.println(prop5.getProperty("message")); 
        prop5.load(ClassLoader.getSystemClassLoader().getResourceAsStream("webtest/test7.properties"));  
        System.out.println(prop5.getProperty("message"));*/

 注意:上面的地址上巧妙的使用了【..】来返回上一级,并使用此方法替代了servlet特有的方法。

eclips中输出:

Properties解析中文一堆问号 properties文件转义字符_Properties解析中文一堆问号_14

war包输出:

Properties解析中文一堆问号 properties文件转义字符_Properties解析中文一堆问号_15

测试一切正常。

②使用java.util.ResourceBundle类的getBundle()方法:

注意:这个getBundle()方法的参数只能写成包路径+properties文件名,也就说不用带文件的后缀。

System.out.println(ResourceBundle.getBundle("test4").getString("message"));
        System.out.println(ResourceBundle.getBundle("properties/test/test5").getString("message"));
        System.out.println(ResourceBundle.getBundle("webtest/test7").getString("message"));
        //以下无法正常获取
        /*System.out.println(ResourceBundle.getBundle("/../../META-INF/test3").getString("message"));
        System.out.println(ResourceBundle.getBundle("../lib/test6").getString("message"));
        System.out.println(ResourceBundle.getBundle("../test2").getString("message"));
        System.out.println(ResourceBundle.getBundle("../../test1").getString("message"));*/

eclips中输出:

Properties解析中文一堆问号 properties文件转义字符_jar包_16

war包输出:

Properties解析中文一堆问号 properties文件转义字符_Properties解析中文一堆问号_17

测试一切正常。

③使用java.util.PropertyResourceBundle类的构造函数:

System.out.println(new PropertyResourceBundle(Index.class.getResourceAsStream("/test4.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Index.class.getResourceAsStream("/properties/test/test5.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Index.class.getResourceAsStream("/webtest/test7.properties")).getString("message")); 
        //以下为servlet独有
        System.out.println(new PropertyResourceBundle(request.getSession().getServletContext().getResourceAsStream("/META-INF/test3.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(request.getSession().getServletContext().getResourceAsStream("/WEB-INF/lib/test6.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(request.getSession().getServletContext().getResourceAsStream("/WEB-INF/test2.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(request.getSession().getServletContext().getResourceAsStream("/test1.properties")).getString("message")); 

        System.out.println(""); 

        System.out.println(new PropertyResourceBundle(Index.class.getClassLoader().getResourceAsStream("test4.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Index.class.getClassLoader().getResourceAsStream("properties/test/test5.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Index.class.getClassLoader().getResourceAsStream("webtest/test7.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Index.class.getClassLoader().getResourceAsStream("../../META-INF/test3.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Index.class.getClassLoader().getResourceAsStream("../lib/test6.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Index.class.getClassLoader().getResourceAsStream("../test2.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Index.class.getClassLoader().getResourceAsStream("../../test1.properties")).getString("message")); 
        
        System.out.println(""); 

        System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("test4.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("properties/test/test5.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("webtest/test7.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("../../META-INF/test3.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("../lib/test6.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("../test2.properties")).getString("message")); 
        System.out.println(new PropertyResourceBundle(Thread.currentThread().getContextClassLoader().getResourceAsStream("../../test1.properties")).getString("message"));

eclips中输出:

Properties解析中文一堆问号 properties文件转义字符_java_18

war包输出:

Properties解析中文一堆问号 properties文件转义字符_开发工具_19

测试一切正常。

测试工程:https://github.com/easonjim/5_java_example/tree/master/propertiestest/web

三、操作:

对于操作,这里不做测试,一般原生方法中,只有Properties类的store方法。