首选项API
在桌面程序中,通常都会存储用户首选项,如用户最后处理的文件、窗口的最后位置等。
利用Properties类可以很容易的加载和保存程序的配置信息,但有以下缺点:
- 有些操作系统没有主目录概念,很难为匹配文件找到一个统一的位置。
- 配置文件没有标准命名,用户安装多个Java应用,就更容易发生命名冲突。
操作系统有一个存储配置信息的中心存储库,最著名例子就是Window系统中的注册表。
Preferences类似于一种平台无关的中心存储库,Windows中,Preferences使用注册表存储信息,Linux上信息存储在本地文件系统中。存储库对程序员是透明的。
Preferences有一个树状结构,节点路径类似于/com/mycompany/myapp。
每个节点都有一个单独的键值对表,可存储数值,字符串,字节数组,不建议存储串行化对象。可以有多个树,每个程序用户都有一棵树,类似于操作系统的当前用户概念。
访问数中的一个节点,需要从用户或系统根开始:
Preferences root = Preferences.userRoot();或者
Preferences root = Preferences.systemRoot();
然后访问节点,可以直接提供一个节点路径名:
Preferences node = root.node("/com/mycompany/myapp");
如果节点路径名等于类的包名,可以简便调用:
Preferences node = Preferences.userNodeForPackage(obj.getClass());或
Preferences node = Preferences.systemNodeForPackage(obj.getClass());
一般来说,obj往往是this引用
得到节点,可以用如下方法访问键值表:
String get(String key,String defval)
int getInt(String key,int defval)
double getDouble(String key,double defval)
byte[] getByteArray(String key,byte[] defval)等
读取信息时必须指定一个默认值。
如下put方法向存储库写数据:
put(String key,String value)
putInt(String key,int value)
可以用一下方法枚举一个节点中存储的所有键
String[] keys()
注释:节点名和键都最多只能有80个字符,字符串值最多可以有8192个字符。
类似Windows注册表的中心存储库通常都存在两个问题:
- 它们会变成充斥着过期信息的垃圾场
- 配置数据域存储库纠缠在一起,所有很难把首选项迁移到新平台。
提供了第二个问题的解决方案,通过一下方法导出一个子树:
void exportSubtree(OutputStream out)
void exportNode(OutputStream out)
数据用XML格式保存,可以已通过调用一下方法将数据导入到另一个存储库:
void importPreferences(InputStream in)
示例文件,略。
案例:保存窗口位置和文件名,导出首选项后,退出并重启应用,导入首选项,窗口和之前一样,待续。。。
package preferences;import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.prefs.Preferences;import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;public class ImageViewer {public static void main(String[] args) {EventQueue.invokeLater(()->{var frame = new ImageViewerFrame();frame.setTitle("图片查看器");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);});}
}class ImageViewerFrame extends JFrame {private static final int DEFAULT_WIDTH = 300;private static final int DEFAULT_HEIGHT = 200;private String image;public ImageViewerFrame() {Preferences root = Preferences.userRoot();Preferences node = root.node("/preferences/ImageViewer");int left = node.getInt("left", 0);int top = node.getInt("top", 0);int width = node.getInt("width", DEFAULT_WIDTH);int height = node.getInt("height", DEFAULT_HEIGHT);setBounds(left, top, width, height);image = node.get("image", null);var label = new JLabel();if(image != null) label.setIcon(new ImageIcon(image));addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {node.putInt("left", getX());node.putInt("top", getY());node.putInt("width", getWidth());node.putInt("height", getHeight());node.put("image", image);}});add(label);//安装文件选择器var chooser = new JFileChooser();chooser.setCurrentDirectory(new File("."));//安装菜单栏var menuBar = new JMenuBar();setJMenuBar(menuBar);var menu = new JMenu("文件");menuBar.add(menu);var openItem = new JMenuItem("打开");menu.add(openItem);openItem.addActionListener(event -> {int result = chooser.showOpenDialog(null);if (result == JFileChooser.APPROVE_OPTION) {image = chooser.getSelectedFile().getPath();label.setIcon(new ImageIcon(image));}});var exitItem = new JMenuItem("关闭");menu.add(exitItem);exitItem.addActionListener(event->System.exit(0));}
}
java.util.prefs.Preferences 1.4
- Preferencs userRoot(),返回调用程序的用户的首选项根节点。
- Preferences systemRoot(),返回系统范围的首选项根节点。
- Preferences node(String path),返回从当前节点由给定路径可以到达的节点。如果path是绝对路径(也就是说,以一个/开头),则从包含这个首选项节点的树的根节点开始查找。如果给定路径不存在相应的节点,则创建这样一个节点。
- Preferences userNodeForPackage(Class cl)
- Preferences systemNodeForPackage(Class cl),返回当前用户树或系统树中的一个节点,其绝对节点路径对应类cl的包名。
- String[] keys(),返回属于这个节点的所有键。
- String get(String key,String defval)
- int getInt(String key,int defval)
- long getLong(String key,long defval)
- float getFloat(String key,float defval)
- double getDouble(String key,double defval)
- boolean getBoolean(String key,double defval)
- byte[] getByteArray(String key, byte[] defval),返回与给定键关联的值,或者如果没有值与这个键关联、关联的值类型不正确或首选项存储库不可用,则返回所提供的默认值。
- void put(String key, String value)
- void putInt(String key, int value)
- void putLong(String key, long value)
- void putFloat(String key,float value)
- void putDouble(String key, double value)
- void putBoolean(String key,boolean value)
- void putByteArray(String key,byte[] value),在这个节点存储一个值/键对。
- void exportSubtree(OutputStream out),将这个节点及其子节点的首选项写至指令的流。
- void exportNode(OutputStream out),将这个节点,不包括其子节点的首选项写至指定的流。
- void importPreferences(InputStream in),导入指定流中包含的首选项。