8.2.3 ResourceBundle类

优质
小牛编辑
130浏览
2023-12-01

ResourceBundle类表示本地环境的一个资源包。一个资源包含有一个或多个Java资源文件。这些资源文件的文件名和本地环境有关。一般可以使用Locale对象来描述本地环境的信息。因此,建立ResourceBundle对象需要提供相应的Locale对象。

1. 资源文件概述

在一个国际化程序中,需要将文本信息保存在文件中,当程序运行时从这些文件中读取相应的文本信息。当然,这个功能使用Java实现非常简单,但国际化程序不仅仅要求从文件中读出信息,还需要根据本地环境选择读取哪一个文件中的信息。如果本地环境是中文,则需要选择保存中文信息的文件。如果本地环境是英文,则需要选择保存英文信息的文件。这就需要这些保存信息的文件按着一定的规则命名,以便系统可以准确地知道哪些文件是保存中文信息的,哪些文件是保存英文信息的。这些保存各种语言信息的文件被称为国际化资源文件,也可以简称为资源文件。

选择资源文件的文件名通常由以下三部分组成:

l 文件基名(baseName)

2 语言(language)

3 国家(country)

文件基名可以是任何有效的文件名,语言是在ISO-639标准中定义的语言代码,国家是在ISO-3166标准中定义的国家代码。文件基名、语言和国家之间用下划线分隔。资源文件的扩展名通常的是properties。如MyResource_zh_CN.properties就是一个合法的资源文件名。该文件表示中文环境下使用的资源文件。MyResource_en_US.properties则表示在英文(美国)环境下使用的资源文件。

在资源文件的三个组成部分中,文件基名是必须的,而语言和国家是可选的。也就是说,一个资源名可以只包含文件基名,不包含语言和国家。或者只包含文件基名和语言,不包含国家。下面的资源文件名都是合法的:

l MyResource.properties

2 MyResource_zh.properties

对于这样的资源文件命名规则,虽然使用编程的方式可以解决,但JDK提供了更好的解决方案来选择并读取这些资源文件。这就是ResourceBundle类。在创建ResourceBundle对象时会根据提供的Locale自动选择相应的资源文件,并通过ResourceBundle类的相关方法读取资源信息。关于ResourceBundle类的详细内容,将在后面的部分介绍。

2. 资源文件的格式

资源文件的格式和java.util.Properties类要求的格式相同,也就是key-value值对。如下面的资源文件分别保存了英文菜单信息:

MyResource_en_US.properties

menu_help=Help

menu_file=File

由于资源文件不支持非西欧字符,如中文、日文字符。因此,在资源文件中保存这些字符时,需要使用“\uxxxx”格式的UCS2编码。其中xxxx表示二个字节的16进制形式。如要保存“帮助”和“文件”信息,就需要按如下的内容编写资源文件:

MyResource_zh_CN.properties

menu_help=\u5e2e\u52a9

menu_file=\u6587\u4ef6

实际上,“\u5e2e\u52a9”和“\u6587\u4ef6”也是Java支持的格式,也就是说,可以直接将“\uxxxx”格式作为Java字符串,Java编译器在处理“\uxxxx”格式时会自动将其转换成Java内部所使用的UCS2编码。如下面的代码所示:

String s = "file:\u6587\u4ef6";

System.out.println(s);

在运行上面的代码后,将输出如下的信息:

file:文件

3. 资源文件的搜索顺序

如果同一种语言的资源文件存在多个,系统会按着如下的顺序搜索:

l baseName_language_country_variant.properties

2 baseName_language_country.properties

3 baseName_language.properties

4 baseName.properties

其中variant是第三方软件、平台或浏览器扩展的标志。详见8.2.1节的内容。

实际上,系统会搜索上面所有的资源文件(如果这些资源文件存在的话),当在这些资源文件中有重复key时,如果在同一个资源文件中有重复,则以最后一个出现的key为准。如果在不同资源文件中的重复,则以搜索顺序靠前的资源文件中的key为准。如MyResource_zh.properties文件中有两个key值为file的资源信息,内容如下:

file = File1

file = File2

系统在读取file资源时会读出“File2”,而不是File1。如果在MyResource.properties文件中也有一个key值为file的资源信息,内容如下:

file = File3

由于MyResource_zh.properties文件比MyResource.properties文件先搜索到,因此,系统仍然会读取MyResource_zh.properties文件最后一个file值,也就是“File2”。

4. 装载和读取资源包

通常可以使用ResourceBundle类的静态方法getBundle来创建ResourceBundle对象实例。在创建ResourceBundle对象实例的过程中会加载相应的资源包。getBundle方法有如下三个常用的重载形式:

public static final ResourceBundle getBundle(String baseName)

public static final ResourceBundle getBundle(String baseName, Locale locale)

public static ResourceBundle getBundle(String baseName, Locale locale,ClassLoader loader)

其中baseName表示资源文件的基名,locale表示与要读取的资源文件相对应的本地信息(Locale对象)。loader表示指定资源文件的类装载器。

如果使用getBundle方法的第一种重载形式,locale和loader参数使用了默认的值。也就是说,locale参数值是使用Locale.getDefault方法获得的值,而loader参数值是使用this.getClass().getClassLoader()方法获得的值。

如果使用getBundle方法的第二种重载形式,则loader参数值用了默认的值,也就是this.getClass().getClassLoader()方法返回的类装载器对象。

getBundle方法在装载资源包时会按着上面所讲的规则。如果Locale对象没有语言和国家信息,则getBundle方法会忽略这些本地信息,而直接读取baseName.properties文件的内容。

当baseName参数值中含有“.”时,系统会自动将“.”替换成“/”,当然,也可以直接在baseName参数值中使用“/”。如下面的两个baseName是相同的:

l  resources.system.MyResource

2  resources/system/MyResource

为了使系统能找到资源文件,必须将资源文件放在系统能找到的目录中,如.class文件的根目录、Web应用程序的WEB-INF\classes目录等。如果系统未找到任何一个资源文件,则系统会抛出java.util.MissingResourceException异常。

在创建了ResourceBundle对象后,可以使用ResourceBundle类的getString方法读取相应的资源信息。如下面代码所示:

java.util.Locale locale = new java.util.Locale("zh", "CN");

java.util.ResourceBundle rb = java.util.ResourceBundle.getBundle("MyResource", locale);

System.out.println(rb.getString("file"));

在创建Locale对象时,语言和国家也可以不是ISO-639和ISO-3166标准中定义的代码,如下面的代码所示:

java.util.Locale locale = new java.util.Locale("abc", "DDD");

java.util.ResourceBundle rb = java.util.ResourceBundle.getBundle("MyResource",locale);

System.out.println(rb.getString("file"));

如果在类加载器可搜索到的目录中有一个MyResource_abc_DDD.properties文件,上面的代码仍然可以输出该文件中的相应资源信息。当然,如果该文件不存在,也会抛出一个MissingResourceException异常。