用 Preferences API 存储对象.docx_第1页
用 Preferences API 存储对象.docx_第2页
用 Preferences API 存储对象.docx_第3页
用 Preferences API 存储对象.docx_第4页
用 Preferences API 存储对象.docx_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

为什么设计 Preferences API?如果说 Preferences API 主要是为让 Java 程序访问 Microsoft Windows 注册表而创建的,一定会让人感到意外。为什么我要这么说呢?这个 API 的设计类似于 Windows 注册表,本文前三段中的大部分说明也同样适用于注册表。不过,Preferences API 就像所有 Java 语言一样,是以跨平台为目的的,所以它在非 Windows 系统上至少可以工作得一样好(当然,本文中的代码是跨平台的)。Preferences API 规范没有规定如何实现这个 API,只规定了它必须做什么。Java 运行时环境(Java Runtime Environment JRE)的每一个实现对这个 API 都可以有不同的实现。许多非注册表的实现将 API 数据存储在一个 XML 格式的文件中,这个文件也许是在用户的主目录中或者在一个共享目录中。与 Windows 注册表一样,Preferences API 使用层次树结构来存储数据。起始点是一个root node(根节点是树的根基,所有其他节点都是这个节点的后代)。节点可以包含命名的值以及其他节点。不同的程序将它们的数据存储在树的不同位置上,所以它们不会彼此冲突。正如我们将要看到的,Preferences API 采用了特殊的方法帮助防止这种冲突。我们将首先简单看一下 Preferences API 是如何工作的以及如何使用它。使用 Preferences理解 Preferences API 的最好方法是使用它。需要做的第一件事是访问根节点:Preferences root = Preferences.userRoot();这一行代码返回数据树的user root。前面我们说系统中的所有数据都存储在一个树中。不过,这并不完全正确 - 事实上,有两个数据树 - 用户树和系统树。这两个树的行为完全相同,但是它们有不同的目的。系统树用于存储所用户都可以使用的数据,而用户树对于每一个用户是不同的。这两个树天生就有不同的目的。您要将字体首选项存储在用户树中,因为这是用户特定的内容。另一方面,您要将程序位置存储在系统树中,因为位置对于所有用户是相同的,并且所有用户都可能用到它。小型程序会使用系统树或者用户树,但是不会同时使用这两者。大型应用程序可能同时使用这两种树。在本文中,我们将只针对用户树,要记住用户和系统树的行为是一样的。现在让我们看一下如何用 Preferences API 读取和写入简单的值。获得一个值当您得到根节点后,就用它读取和写入值。下面是如何写入一个字体大小:root.putInt( fontsize, 10 );下面是在这之后将它读出来的方法:int fontSize = prefs.getInt( fontsize, 12 );注意getInt()需要一个默认值 - 在这里是12。当然,您可以读取和写入整数之外的值。可以读取和写入许多基本 Java 类型。还可以将节点存储在其他节点中,如这个例子所示:Preferences child = parent.node( child );这就是 Preferences API 的全部内容 - 剩下的就是细节使用了,我们将在下一节讨论其中一个细节。获得一个包的节点不难想像两个不同的程序员可能希望存储不同的字体大小,如果他们决定以同一个名字“font size”存储他们的值,那么我们就有问题了。一个程序的首选项会影响另一个程序。解决方法是将内容存储在包特定的位置上,像这样:Preferences ourRoot = Preferences.userNodeForPackage( getClass() );userNodeForPackage()方法取一个Class对象并返回这个类特定的节点。这样,每一个应用程序 - 假定它是在其自己的包中 - 都会有自己的首选项节点。对于 Preferences API 的工作方式有了很好的了解后,我们还需要知道如何扩展它以便对对象进行处理。存储对象这就是我们希望将对象写入 Preferences 树的理想方法:清单 1. 将对象写入 Preferences 树的理想方法Font font = new Font( . );Preferences prefs = Preferences.userNodeForPackage( getClass() );prefs.putObject( font, font );不过,不幸的是,Preferences 对象没有putObject()和getObject()方法。但是我们会尽量做到接近这一点。我们将在一个名为PrefObj的类中实现这些方法。以下是我们的做法:清单 2. 实现 putObject() 和 getObject()Font font = new Font( . );Preferences prefs = Preferences.userNodeForPackage( getClass() );PrefObj.putObject( prefs, font, font );我们已经尽量做到在Preferences类中得到一个添加方法。下一节,我们将看一看getObject()和putObject()是如何实现的。将对象转换为字节数组我们在这里使用的技术用到了两个技巧。第一个技巧是将对象转变为一个字节数组。这样做的原因很简单:尽管 Preferences 对象不处理对象,但是它可以处理字节数组。幸运的是,我们不需要从头开始 - 它已经建立在 Java 语言中了。有几种方式将对象转换为字节数组,下面展示了我们在PrefObj类中是如何做的:清单 3. 将对象转换为字节数组static private byte object2Bytes( Object o ) throws IOException ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream( baos ); oos.writeObject( o ); return baos.toByteArray();这里的关键是ObjectOutputStream类 - 它是实际完成将对象转换为字节流这个魔术的类。通过用ObjectOutputStream包住ByteArrayOutputStream,我们就将字节流转换为字节数组。还有一种使用其他方式的方法:清单 4. 将字节数组转换为对象static private Object bytes2Object( byte raw ) throws IOException, ClassNotFoundException ByteArrayInputStream bais = new ByteArrayInputStream( raw ); ObjectInputStream ois = new ObjectInputStream( bais ); Object o = ois.readObject(); return o;一定要记ObjectOutputStream只处理实现了 java.io.Serializable 接口的对象。幸运的是,这包括了几乎所有核心 Java 库中的对象以及您的程序中所有声明为实现 Serializable 的对象。正如我在前面提到的,Preferences API 的确可以对字节数组进行处理。不过,我们在这里构造的字节数组并不是很正确,我们将在下一节看到这一点。将对象拆分为片段Preferences API 对可以存储在它里面的数据大小有限制。具体就是字符串限制为 MAX_VALUE_LENGTH 字符。字节数组限制为 MAX_VALUE_LENGTH 长度 75%,因为字节数组是通过编码为字符串存储的。另一方面,一个对象可以为任意大小,所以我们需要将它分为几部分。当然,最容易的方法是首先将它转换为一个字节数组,然后将字节数组拆开。下面是拆开字节数组的代码,它也来自于PrefObj:清单 5. 将字节数组拆分为可消化的大小static private byte breakIntoPieces( byte raw ) int numPieces = (raw.length + pieceLength - 1) / pieceLength; byte pieces = new bytenumPieces; for (int i=0; i raw.length) endByte = raw.length; int length = endByte - startByte; piecesi = new bytelength; System.arraycopy( raw, startByte, piecesi, 0, length ); return pieces;这里没有什么复杂的内容 - 我们只是创建一个数组的数组,每一个长度为最大 pieceLength的字节长度(pieceLength 是 MAX_VALUE_LENGTH 的3/4)。相应地,有另一种方法将各个部分再合并到一起:清单 6. 将片段重新组装为完整的字节数组static private byte combinePieces( byte pieces ) int length = 0; for (int i=0; ipieces.length; +i) System.arraycopy( piecesi, 0, raw, cursor, piecesi.length ); cursor += piecesi.length; return raw;这个例程检查所有片段的总长度并创建一个具有这种长度的新数组。然后将片段一个一个地拷贝进去。读取和写入片段这里我们使用第二个技巧 - 将值转换为节点。一般来说,当我们用 Preferences API 存储值时,我们将它放到首选项数据树中一个节点的 slot 中。但是我们不能在这里真的这样做。即使一个对象只有一个值,我们也要将它转换为一组固定长度的字节数组。如果我们只有一个字节数组,写入数据树中的 slot 会很容易,因为 Preferences API 直接支持字节数组。但是这行不通,因为我们有多个数组。技巧是为每一个对象分配一个节点。让我们弄清楚它的意义。通常,将值存储在节点的多个 slot 的其中之一。但是我们准备为每一个对象创建一个节点, 并将字节数组存储到该节点的 slot 中。让我们说的更具体一些。如果可以,我们会将一个对象存储到单个 slot 中:清单 7. 将一个对象存储到单个 slot 中Preferences parent = .;parent.putObject( child, object );但是我们不能这么做,因为 Preferences 没有putObject()方法。相反,我们创建一个节点并将字节数组存储到其中,如下所示:清单 8. 将字节数组存储到一个节点中Preferences parent = .;Preferences child = parent.node( child );for (int i=0; ipieces.length; +i) child.putByteArray( +i, piecesi );这样,不是将一个值存储到一个称为“child”的 slot 中,我们将几个值存储到一个称为 “child”的节点中。这些值是用数字键 - “0”、“1”、“2”等存储的。使用数字键可以使后面读取片段时更容易:清单 9. 读取容易读的片段Preferences parent = .;Preferences child = parent.node( child );for (int i=0; inumPieces; +i) piecesi = child.getByteArray( +i, null );在下一节,我们将看一下结合所有这些步骤的例程。将所有内容合到一起PrefObjs有一个名为putObject()的静态方法,它调用在前面清单3、5和8中描述的方法。其内容如下:清单 10. 方法 putObject() 使用其他方法来写入片段static public void putObject( Preferences prefs, String key, Object o ) throws IOException, BackingStoreException, ClassNotFoundException byte raw = object2Bytes( o ); byte pieces = breakIntoPieces( raw ); writePieces( prefs, key, pieces );方法putObject()将整个过程分为三步,分别嵌入我们在前面讨论过的三个方法。它将对象转换为字节数组(清单3)、将数组分解为更小的数组(清单5)、然后将片段写入 Preferences API。有一个用于读取的类似方法:清单 11. 方法 getObject() 对写入片段做同样的事情static public Object getObject( Preferences prefs, String key ) throws IOException, BackingStoreException, ClassNotFoundException byte pieces = readPieces( prefs, key

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论