kenlistian

勤学多思

  IT博客 :: 首页 :: 新随笔 ::  :: 聚合  :: 管理 ::
  412 随笔 :: 0 文章 :: 23 评论 :: 0 Trackbacks
把关于序列化的章节整理了下,大致了解了使用RMS类的方法。
至于如何在代码中实现,今个儿没时间搞。先放放。


MIDP2.0 规范里提供了RMS
以一种简单的,类似表格的形式组织信息,并存储起来形成持久化存储。

理解Records(记录)和 Records Stores(记录仓储)两个概念。

记录仓储(Records Stores)类似于数据库的表 table。
名称大小不能超过 32 个Unicode 字符,同一个Suite下的MIDlet 都可以共享这些记录仓储。

记录即表中记录。
记录(Record)由一整型的 RecordID 与一代表数据的 byte[]数组两个子元素组成。
RecordID 是记录的唯一标志符,就相当是数据表中递增的id关键字。

调用javax.microedition.rms即操作数据存储。
该包中有一主类, 四个接口,以及五个可能的被抛出异常。


打开

通过openRecordStore()来取得实例。

openRecordStore (String recordStoreName, boolean createIfNecessary)
openRecordStore (String recordStoreName, boolean createIfNecessary,int authmode), boolean writable))
openRecordStore (String recordStoreName, String vendorName, String suiteName)

第一个参数是记录仓储的名称,
第二个参数表明了当我们请求的仓储不存在时,是否新建一 Record Store;
第三个参数表明了此仓储的读取权限,
第四个参数则决定了写入权限。

当用第一个方法时, 则选择读取权限只限于本地,且拒绝其他MIDlet写数据到记录仓储上。
即相当于使用第二种开启方法并分别为第三第四个参数传入了RecordStore.AUTHMODE_PRIVATE 和 false。

第三openRecordStore 读取其他 MIDlet Suite 记录仓储。
传入参数为记录仓储名,发布商名以及 MIDlet Suite 套件名。


注意,如该储的读取权限为 AUTHMODE_PRIVATE 的话,此方法将返回安全错误。

用第一种方法的示例:
   private RecordStore rs = null;
   try {
     //打开一个RMS,如果打开失败,则创建
      rs = RecordStore.openRecordStore(“testRMS”, true);
    }
    catch (RecordStoreNotFoundException e) {
        e.printStackTrace();

    }
    catch (RecordStoreFullException e) {
        e.printStackTrace();
    }
    catch (RecordStoreException e) {
       e.printStackTrace();
   }


关闭 closeRecordStore()

打开需要关闭,就如同你new一个内存,要记得delete,不要指望自动回收功能。

try {
    rs = RecordStore.openRecordStore(“testRMS”, true);

       //.....
       rs.closeRecordStore();
    }
      catch (RecordStoreNotOpenException e) {
      e.printStackTrace();
    } catch (RecordStoreException e) {
      e.printStackTrace();
   }


删除deleteRecordStore()

在删除之前,确保当前的仓储是处于关闭状态,否则抛异常。
如下

//假定rs是已经存在的记录仓储,并已经打开
try
{
   rs.closeRecordStore();
   RecordStore.deleteRecordStore(“testRMS”);
   
}
catch (RecordStoreNotOpenException e) {
   e.printStackTrace();
    }
catch (RecordStoreNotFoundException e) {
    e.printStackTrace();
} catch (RecordStoreFullException e) {
    e.printStackTrace();
} catch (RecordStoreException e) {
     e.printStackTrace();
}


插入 addRecord(byte[] data, int offset, int numBytes)

添加byte数组类型的数据。
参数为byte[]数组,传入 byte[]数组起始位置,传入数据的长度

数据添加成功后, addRecord 将返回记录 ID号 (RecordID) ,

添加操作是一个原子操作。但在又读又写是同步的。


删除 deleteRecord(int recordId),

如试图从未开启的记录仓储中删除记录,返回RecordStoreNotOpenException异常;
如果传入ID无效的,返回 InvalidRecordIDException异常;

修改指定ID的记录值
    setRecord(int recordId, byte[] newData, int offset, int numBytes)




针对 RecordStore 的操作只提供对针对 byte 数组的服务.
遇到的都将是非 byte 类型。

采用流文件类来处理。

非byte-->byte
ByteArrayOutputStream,   
DataOutputStream,

byte-->非byte
ByteArrayInputStream,
DataInputStream


示例

首先写入一组自定义数据,然后在读出:
  ByteArrayOutputStream baos = new ByteArrayOutputStream();   //构建一个转换成byte字节的流
  DataOutputStream dos = new DataOutputStream(baos);           //构建写入流的数据类

  dos.writeBoolean(false);
  dos.writeInt(15);
  dos.writeUTF("abcde");

  byte [] data = baos.toByteArray();//取得byte数组
  dos.close();
  baos.close();

  
  ByteArrayInputStream bais = new ByteArrayInputStream(data); //构建一字节写入流
  DataInputStream dis = new DataInputStream(bais);           //能读流数据类
  
  boolean flag = dis.readBoolean();
  int intValue = dis.readInt();
  String strValue = dis.readUTF();
  dis.close();
  bais.close();
   

用RMS实现对象序列化
下面展示单词记录本,构建一个word类数据结构

public class Word {
  private String  enWord;   //英文单词
  private String  cnWord;   //解释
  private long   dateTime;   //读取时间
  private String  detail;    //备注信息
}

读出和写入调用serialize,deserialize
serialize 用于序列化对象数据,返回 byte 数组类型;
deserialize 完成的则是相反的工作。

/*
  生成序列化的byte数组数据
*/
  public byte[] serialize() throws IOException{
   
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);
   
    dos.writeUTF(this.enWord);
    dos.writeUTF(this.cnWord);
    dos.writeLong(this.dateTime);
    dos.writeUTF(this.detail);
   
    baos.close();
    dos.close();
    return baos.toByteArray();
}

/* 将传入的byte类型数据反序列化为已知数据结构
*/
  public static Word deserialize(byte[] data) throws IOException{
   
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    DataInputStream dis = new DataInputStream(bais);
   
    Word word = new Word();
    word.enWord = dis.readUTF();
    word.cnWord = dis.readUTF();
    word.dateTime = dis.readLong();
    word.detail = dis.readUTF();
   
   bais.close();
   dis.close();
   return word;

  }


RecordStore的更多操作


RecordComparator,
RecordEnumeration,
RecordFilter
RecordListener。

考虑到 RecordComparator、RecordFilter 都是作用在 RecordEnumeration 上的,我们先来介
绍这个接口。

RecordEnumeration遍历接口
采用for方式,由于RecordId所对应的记录并不见得存在,故采用RecordEnumeration 接口。
有点类似迭加器了。


enumerateRecords():
通过对 RecordStore 实例对象调用 enumerateRecords 方法来取得一个 RecordEnumeration 的
实例。
其可传入 3 个参数:filter,comparator与 keepUpdated。

前两个参数分别是过滤器和排序策略,
这个后面会讲到。

当传入的 filter不为空时,它将用于决定记录仓储中的哪些记录将被使用;
当 comparator 不为空时,RecordStore将按照我们指定的排列顺序返回。
第三个参数决定了当遍历器建立起来以后,是否对记录仓储新的改变做出回应。
如果传入 true,那么将有一个 RecordListener 被加入到 RecordStore 中,使得记录仓储的内容与
RecordEnumeration 随时保持同步。
如果传入 false,则可以使得当前遍历更有效率,但所取得的RecordID 集合仅仅是调用此方法这个时刻的RecordStore 快照。

此后对 RecordStore 所有更改都不会反应在这个集合上。
请读者根据要求在访问数据完整性和访问速度之间进行取舍。

numRecords():          返回了在当前遍历集合中,可用记录数目。这里所指的可用,不仅仅是说RecordID
                        对应的记录存在;当 filter存在时,也需要符合过滤条件。

hasNextElement():      判断在 RecordEnumeration 当前指向的下一个位置, 还有没有剩余记录了。

hasPreviousElement():  判断在 RecordEnumeration当前指向的前一个位置,还有没有剩余记录了。


nextRecord():             返回了遍历器下一位置的记录拷贝,由于返回的是拷贝,
                        所以任何对返回记录的修改都不会影响到记录仓储的实际内容。

nextRecordId():        返回当前遍历器下一位置记录的RecordID,当下一位置没有可用的记录时,
                        继续调用nextRecordId将抛出异常 InvalidRecordIDException。

添加一个方法 ViewAll(), 用来返回当前记录仓储中的所有单词
如何利用 RecordEnumeration 来遍历记录。

public Word[] viewAll() throws IOException {
    Word[] words = new Word[0];
    RecordEnumeration re = null;

    //rs是之前创建的RecordStore类型实例变量
    if (rs == null)
        return words;

    try {
       re = rs.enumerateRecords(null, new WordComparator(), false);
       //无过滤器、但有一个排序策略
      words = new Word[re.numRecords()];
      int wordRecords = 0;
   
      while (re.hasNextElement()) {
         byte[] tmp = re.nextRecord();
         words[wordRecords] = Word.deserialize(tmp);
         wordRecords++;
      }
    }
    catch (RecordStoreNotOpenException e1) {
       e1.printStackTrace();
    }
    catch (InvalidRecordIDException e1) {
       e1.printStackTrace();
    }
    catch (RecordStoreException e1) {
       e1.printStackTrace();
    }
    finally {
      if (re != null)
         re.destroy();
   }
   return words;
}

RecordFilter 过滤接口
  过滤接口是用来过滤不满足条件的记录的。
  要实现match(byte[] candidate)方法,当传入 byte 数据符合筛选条件时,返回 true。

  WordFilter 实现 RecordFilter 接口。

  public class WordFilter implements RecordFilter
  {
    private String  enWord;
    private int     type;
    public WordFilter(String enword, int type){
  
    //传入要比较的项,type指向一个自定义的内部事件标记
    //表现为整形
      this.enWord = enword;
      this.type   = type;
   }
   
   public boolean matches(byte[] word) {
   //matches方法中传入的参数是RMS中的各个候选值(元素)
   try {
   
       if(type == EventID.SEARCH_EQUAL){
            return Word.matchEN(word, enWord);
       }
       else{
         return Word.matchEN_StartWith(word, enWord);
       }
    }
    catch (IOException e) {
       e.printStackTrace();
       return false;
    }
   }
}

示例中的 EventID.SEARCH_EQUAL 为一个定义好的整型数据;
同时,这里涉及到了Word 类的两个对应方法:

public static boolean matchEN_StartWith(byte[] data, String enword) throws IOException
{
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    DataInputStream dis = new DataInputStream(bais);
    try{
         return (dis.readUTF().startsWith(enword));

     }catch(IOException e){
        e.printStackTrace();
        return false;
     }
}
  
public static boolean matchCN(byte[] data, String cnword) throws IOException
{
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    DataInputStream dis = new DataInputStream(bais);
    try{
         dis.readUTF();
         return (dis.readUTF().equals(cnword));
   }catch(IOException e){
       e.printStackTrace();
       return false;
   }
}


RecordComparator比较接口
   
   比较器定义了一个比较接口,用于比较两条记录是否匹配,或符合一定的逻辑关系。

   须实现compare方法
   compare(byte[] rec1,  byte[] rec2)
   当rec1 在次序上领先于rec2 时,返回RecordComparator.PRECEDES;
   反之则返回RecordComparator.FOLLOWS;
   参数相等,返回RecordComparator.EQUIVALENT。

   private static class WordComparator implements RecordComparator{
     
      public int compare(byte[] word_1, byte[] word_2) {
   
     try {
        Word word1 = Word.deserialize(word_1);
        Word word2 = Word.deserialize(word_2);
        long dateTime1 = word1.getDateTime();
        long dateTime2 = word2.getDateTime();
     
        if(dateTime1 < dateTime2){
           return RecordComparator.FOLLOWS;
         }
   
    if(dateTime1 > dateTime2){
          return RecordComparator.PRECEDES;
        }
        return RecordComparator.EQUIVALENT;
     }
     catch (IOException e)
     {
        e.printStackTrace();
      }
      return 0;
    }
}





RecordListener 监听器接口

RecordListener是用于接受监听记录仓储中记录添加,更改或删除记录等事件的接口。
利用 RecordStore 的addRecordListener 方法来注册一个监听器。
使用监听器必须实现 3 个方法:
recordAdded,
recordChanged
recordDeleted,

都需传入两个参数:记录仓储名称 recordStroe 与记录号recordId。

  recordAdded:当一条新的记录被添加到仓储空间的时候,该方法被触发。
  recordChanged:当一条记录被修改时使用。
  recordDeleted:当一条记录从记录仓储中删除时调用。

注意,RecordListener 是在对记录仓储的操作动作完成以后被调用的!
特别在recordDeleted 方法中,由于传入的记录已经删除,如再使用
getRecord()试图取得刚刚被删除记录的话,会抛出 InvalidRecordIDException 异常。




  getLastModified():   返回记录仓储最后更新时间。
  getName():           返回一个已经打开了的记录仓储名称。
  getNumRecords():     返回当前仓储中记录总数。
  getSizeAvailable():  返回当前仓储中可用的字节数。
  getVersion():        返回记录仓储版本号。
  listRecordStores():  获取该MIDlet套件中所有的记录仓储列表。
posted on 2008-06-24 22:27 kenlistian 阅读(293) 评论(0)  编辑 收藏 引用 所属分类: Java
只有注册用户登录后才能发表评论。