属性映射

属性映射(property map)是一种存储键/值对的数据结构。属性映射通常用来存储配置信息,它有3个特性:

  • 键和值是字符串。
  • 映射可以很容易地存入文件以及从文件加载。
  • 有一个二级表保存默认值。

在 Java 中使用 Properties 来实现属性映射:

  1. Properties settings = new Properties();
  2. settings.setProperty("width", "200");
  3. settings.setProperty("title", "Hello world");

当然,可以使用 store() 将属性映射列表保存到一个文件中:

  1. OutputStream out = new FileOutputStream("program.properties");
  2. settings.store(out, "Program Properties");

该文件会在项目主目录下创建一个名为 program.properties 的文件,文件内容为:

  1. #Program Properties
  2. #Tue Sep 01 11:23:07 CST 2020
  3. width=200
  4. title=Hello world

当然也可以使用 load() 来加载文件:

  1. InputStream in = new FileInputStream("program.properties");
  2. settings.load(in);

可以使用 System.getProperties() 来调用系统信息,比如使用 user.home 来调用用户主目录:

  1. String userDir = System.getProperties(); // like get /home/yikang

如果想拿到某个属性,就可以使用 getProperty() 来获取数据:

  1. settings.getProperty("title");
  2. settings.getProperty("title", "Defalut title"); // 设置默认值

当然,如果觉得设置默认值麻烦,可以把所有默认值都放在一个二级属性映射中,并在主属性映射的构造器中提供这个给二级映射:

  1. Properties defalutSettign = new Properties(); // 二级属性映射
  2. defalutSettign.setProperty("width", "300");
  3. defalutSettign.setProperty("height", "200");
  4. defalutSettign.setProperty("title", "Default title");
  5. Properties settings = new Properties(defalutSettign); // 主属性映射

这样通过提供一个属性映射来达到提供默认值的目的,甚至可以为 默认值指定默认值。当然,一般没人会这么做。

出于历史原因,Properties 是一个遗留类,它实现了 Map<Object, Object>。因此它可以使用 Map 的 get 和 put 方法。不过,get 方法会返回类型 Object,而put方法允许插入任何对象。最好坚持使用 getProperty 和 setProperty 方法,这些方法会处理字符串,而不是对象。

首选项 API

Properties 虽然很容易地加载和保存配置信息。不过,还是有一下缺点:

  • 有些操作系统没有主目录的概念,所以很难找到一个统一的配置文件位置。
  • 关于配置文件的命名没有标准约定,用户安装多个Java应用时,就更容易发生命名冲突。

Perferences 以一种平台无关的方式提供了这样一个中心存储库。Preferences 存储库有一个树状结构,节点路径名类似于/com/mycompany/myapp。类似于包名,可以有效的避免命名冲突。
存储库里也是用键/值进行储存。可以用来存储数值、字符串或字节数组,但不能存储可串行化的对象。
为了增加灵活性,可以有多个并行的树。每个程序用户分别有一棵树;另外还有一棵系统树,可以用于存放所有用户的公共信息。 Preferences 类使用操作系统的“当前用户”概念来访问适当的用户树。
要访问树中的一个节点,需要从用户或系统根开始:

  1. Preferences root_user = Preferences.userRoot(); // 用户
  2. Preferences root_system = Preferences.systemRoot(); // 系统

然后就可以访问节点:

  1. Preferences node = root.node("/com/mycompany/myapp"); // 直接提供节点路径点
  2. // 路径名等于类的包名,可以通过以下便捷方式来获得节点
  3. Preferences node1 = Preferences.userNodeForPackage(obj.getClass()); //
  4. Preferences node2 = Preferences.systemNodeForPackage(obj.getClass());

一般来说,obj 往往是 this 引用。

然后就可以通过以下方法访问键/值:

  1. String get(String key, String defaval);
  2. int getInt(String key, int defaual);
  3. long getLong(String key, long defaual);
  4. float getFloat(String key, float defaual);
  5. double getDouble(String key, double defaual);
  6. boolean getBoolean(String key, boolean defaual);
  7. byte[] getByteArray(String key, byte[] defaual);

值得注意的是,读取信息时必须指定一个默认值。

当然也有对应的 put 方法想存储库写数据:

  1. put(String key, String value);
  2. putInt(String key, int value);
  3. ...

可以通过 keys() 来拿到一个节点中存储的所有键。
Preferences 可以导出/导出一个子树的首选项来更灵活的使用 Preferneces :

  1. // 导出
  2. void exportSubtree(OutputStream out); // 导出子树
  3. void exportNode(OutputStream out); // 导出节点
  4. // 导入
  5. void importPrefrences(InputStream in);
  6. // like export
  7. OutputStream out = new FileOutputStream("program.xml");
  8. node.exportSubtree(out);
  9. // like import
  10. InputStream in = new FileInputStram("program.xml");
  11. Preferences.importPreferences(in);