前言

对一款人性化的应用来说,往往需要存储用户的偏好设置,例如字体大小、应用风格等个性化的设置数据。Java应用具有跨平台的特性,就更需要一种平台无关的存储手段。Java官方给出的解决方案是Preferences首选项,本文就来简单讲解一下Preferences的使用。

Preferences的存储模式

首先,我们需要知道Preferences为什么可以实现跨平台存储数据。实际上,在不同的操作系统中,Preferences底层的存储方式是不一样的。例如,在Windows下是将数据存储在注册表中,而在Linux下则是将数据存储在文件系统中的。当然,对于程序员来说,这些都是透明的。

Preferences中,使用了树状结构来进行数据的存储,这主要是为了避免文件名冲突。我们需要知道的是,Preferences中有着两棵独立的树。一棵是用户首选项树,一棵是系统首选项树。在用户首选项树中,一般存储应用程序的个性化设置,如字体大小、字体颜色等。而系统首选项树是全局共享的,一般用来设置应用程序的配置数据。通常我们使用用户首选项树即可。

在每棵首选项树中,存在着许多节点,我们的数据就存储在这些节点中。每个节点都有一个节点名,并且节点名可以不唯一,但是节点名中不可以包含“/”字符。同时,每个节点都有一个绝对路径名,这是唯一的。首选项树的根节点绝对路径名是“/”,它的子节点则是“/”+子节点名,其他节点的绝对路径命名方式与此类似。对根节点之外的任何一个节点来说,其绝对路径都是父节点的绝对路径+“/”+当前节点名。在每个节点对应的Preferences对象中,使用键值对的方式来存储和获取数据,这类似于HashMap的使用方式。

基本操作

获取Preferences对象

首先我们需要获取一个Preferences对象。Preferences提供了两个静态方法用于获取首选项树的根节点。

//获取用户首选项树根节点
public static Preferences userRoot()
//获取系统首选项树根节点
public static Preferences systemRoot()

得到根节点后,就可以通过node方法获取我们需要的子节点了。node方法原型如下:

public abstract Preferences node(String pathName);

对于node方法,我们可以传入节点的相对路径名或绝对路径名。以“/”字符开头的就是绝对路径名,而不以“/”开头的则是相对于当前节点的相对路径名。如果该节点不存在,系统将会创建该节点,否则就返回已存在的节点。接下来我们尝试以当前包名作为路径获取一个子节点对应的Preferences对象:

public class PreferencesDemo {public static void main(String[] args) {String absolutePath="/com/example/preferences";Preferences preferences=Preferences.userRoot().node(absolutePath);System.out.println(preferences);}
}

输出结果:

User Preference Node: /com/example/preferences

可以看到,通过将当前包名作为绝对路径,我们已经成功获得了一个Preferences对象。接下来,我们就可以通过这个对象写入和读取数据了。

写入数据/读取数据

Preferences提供了一系列putXXX方法用于写入不同类型的数据,方法原型如下:

abstract void put(String key, String value)
abstract void putBoolean(String key, boolean value)
abstract void putByteArray(String key, byte[] value)
abstract void putDouble(String key, double value)
abstract void putFloat(String key, float value)
abstract void putInt(String key, int value)
abstract void putLong(String key, long value)

相应的,Preferences也提供了一系列getXXX方法读取不同类型的数据,方法原型如下:

abstract String get(String key, String def)
abstract boolean getBoolean(String key, boolean def)
abstract byte[] getByteArray(String key, byte[] def)
abstract double getDouble(String key, double def)
abstract float getFloat(String key, float def)
abstract int getInt(String key, int def)
abstract long getLong(String key, long def)

需要注意的是,所有的getXXX方法都需要传入一个默认值,这是为了在首选项不可用时依旧不会影响应用的正常运行,有利于提高程序的鲁棒性。以下演示向首选项写入和读取字符串:

String defStr=preferences.get("key_str","默认值");
preferences.put("key_str","新的值");
String newStr=preferences.get("key_str","默认值");
System.out.println(defStr);
System.out.println(newStr);

输出结果:

默认值
新的值

刷新数据

Preferences中,默认使用异步的方式写入数据,某些时候我们希望数据可以马上更新,就需要对数据进行刷新操作。这时,就可以使用flush这个方法,其原型如下:

abstract void flush()

删除数据

Preferences提供了两个删除数据的方法。remove用于删除指定键对应的值,removeNode则用于删除当前节点。这两个方法的原型如下:

abstract void remove(String key)
abstract void removeNode()

导入/导出首选项数据

某些时候,我们希望从外部导入应用的偏好设置,或者将当前应用的偏好设置导出进行备份。这时我们就可以使用Preferences提供的导入/导出方法。在这个过程中,数据的载体是XML文件。

static void importPreferences(InputStream is)
abstract void exportNode(OutputStream os)
abstract void exportSubtree(OutputStream os)

importPreferences用于将XML文件中的数据导入首选项系统。exportNode用于导出当前节点存储的数据,但是并不会导出当前节点的子节点中的数据exportSubtree则会导出当前节点及其子节点的所有数据。以下演示如何将当前节点的数据导出到文件中:

public class PreferencesDemo {public static void main(String[] args) {.........try {FileOutputStream outStream=new FileOutputStream("preferences.xml");preferences.exportNode(outStream);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (BackingStoreException e) {e.printStackTrace();}}
}

以上程序会将当前节点的数据导出到项目根目录下的“preferences.xml”文件中,文件内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
<preferences EXTERNAL_XML_VERSION="1.0"><root type="user"><map/><node name="com"><map/><node name="example"><map/><node name="preferences"><map><entry key="key_str" value="新的值"/></map></node></node></node></root>
</preferences>

一个典型的例子

接下来,我们演示一个Preferences的使用场景。在程序首次运行时,将会输出欢迎语句,但是当程序再次运行时,将会输出其他内容。

public class PreferencesDemo {public static final String KEY_FIRST_RUN="is_first_run";public static void main(String[] args) {String absolutePath="/com/example/preferences";Preferences preferences=Preferences.userRoot().node(absolutePath);//判断程序是否是第一次运行boolean isFirstRun=preferences.getBoolean(KEY_FIRST_RUN,true);if(isFirstRun){System.out.println("欢迎使用本程序!");preferences.putBoolean(KEY_FIRST_RUN, false);}else{System.out.println("这已经不是一次运行了哦~");}}
}

第一次运行:

欢迎使用本程序!

第二次运行:

这已经不是一次运行了哦~

Java首选项Preferences相关推荐

  1. XamarinEssentials教程设置首选项Preferences的值

    XamarinEssentials教程设置首选项Preferences的值 如果要对首选项的某一项的值进行设置时,可以通过Preferences类的Set()方法实现,该方法可以对指定键的值进行设置. ...

  2. XamarinEssentials教程首选项Preferences判断项目是否存在

    XamarinEssentials教程首选项Preferences判断项目是否存在 首选项也可以称为偏好设置.它以键值对的形式保存数据,适用于用户少量数据的存储.例如,将用户的个性化设置保存后,每次打 ...

  3. colab清理gpu缓存_Maya2014全面使用手册_GPU 缓存首选项(GPU Cache Preferences)_软件教程_资源库...

    摘要:Maya2014全面使用手册_GPU 缓存首选项(GPU Cache Preferences)_软件教程_资源库 相关视频教程学习推荐: 造型设计<鹫>造型上色完整流程[实名认证] ...

  4. Webots下关于Scene Tree(场景树)和首选项的介绍

    场景树(Scene Tree) 要访问"场景树窗口",可以在Tools菜单中选择Scene Tree, 也可以按主工具栏中的Show the Scene Tree side bar ...

  5. Ps 首选项设置建议

    Windows Ps菜单:编辑/首选项 macOS Ps菜单:Photoshop/首选项 快捷键:Ctrl/Cmd + K 对 Ps 的首选项 Preferences进行设置,可以提高修图与设计效率. ...

  6. Eclipse 配置首选项

    一定制快捷键 一.定制快捷键 1.eclipse 中点击window 2.点击首选项 preferences,然后点击如下图所示: 至此就可以根据自己的喜好制定 eclipse 中的快捷键.

  7. java插件获取首选项_Eclipse RCP 中创建自定义首选项,并能读取首选项中的值

    Eclipse RCP的插件中若想自己定义首选项需要扩展扩展点: org.eclipse.core.runtime.preferences //该扩展点用于初始化首选项中的值 org.eclipse. ...

  8. java怎么写自定义布局_java-Android设置自定义首选项布局

    我正在研究Android项目.我有一个prefs.xml代码,像这样 android:key="pref_name_color_picker" android:title=&quo ...

  9. OSX下代码打开系统首选项(system preferences)

    OSX下代码打开系统首选项(system preferences) 我们开发的App通常会有个设置选项的功能.一般连网的App,产品都会要求在设置选项中加一个打开系统首选项(system prefer ...

  10. 【解决】Java开发工具包(JDK)目录未设置或无效。请在“首选项“>“外部工具“中将其修复

    游戏引擎:Unity 版本:2019.4.6f1 [2017版本以上均可] 编译平台:Visual Studio 2019 问题截图 问题描述 Java开发工具包目录未设置或无效.请在"首选 ...

最新文章

  1. 【tensorflow】全连接层函数tf.layers.dense()原理
  2. html table导出到Excel中,不走后台,js完成
  3. datatables 获取筛选后的数据
  4. delphi android动态权限,DELPHI安卓动态权限申请
  5. PL/Sql快速执行 insert语句的.sql文件
  6. Leetcode: Reorder List Summary: Reverse a LinkedList
  7. yabailv 运放_运放块压摆率单位增益频宽和逻辑器件传输延时
  8. 一块蛋清皂,把毛孔洗得一干二净
  9. 基于lstm+crf实现电子病历实体信息识别 完整的代码+数据集+说明 毕设
  10. ORACLE分配DBA权限
  11. 用C语言基础及数学公式来简单实现土味表白
  12. 新C++(5):异常
  13. arange()用于生成一维数组 reshape()将一维数组转换为多维数组
  14. Photoshop touch教程全攻略
  15. 诺基亚n1支持java功能_诺基亚(NOKIA)N1平板电脑按键及接口评测-ZOL中关村在线
  16. 测试入门——翻页功能测试用例
  17. Verilog中dump vcd格式的波形文件
  18. 员工离职倾向分析,太可怕了!
  19. 市场规模将达360亿!看鲜花电商如何玩转大数据
  20. objection 改源码解决 app的双进程保护 和 双进程保护原理 frida.core.RPCException: Error: expected a pointer

热门文章

  1. Livezilla安装配置, APE(Ajax Push Engine)安装配置
  2. java 长字符串变短_如何将一个很长的String变短,再根据短的String还原?
  3. 5G移动通信技术基本介绍(附92页PDF下载)
  4. 刚买的新电脑win10系统卡的不行,谷歌浏览器搜索贼慢
  5. 英雄无敌6服务器在哪个文件夹,win7系统英雄无敌6无法运行的解决方法
  6. 盛迈坤电子商务:网店有哪些营销活动
  7. 一些wincap函数说明
  8. 用EasySysprep封装Win7系统
  9. win10怎么一键释放运行内存
  10. 深度数据全方位解析:冰桶挑战---TOMsInsight 2014.08.20