`
fanjava
  • 浏览: 235923 次
  • 来自: ...
文章分类
社区版块
存档分类
最新评论

RMS从入门到精通之三

阅读更多

前面两篇文章详细的介绍了Record Management System的基本概念以及对象序列化的问题,现在我们主要介绍关于RecordStore类的使用,在SUN的网站提供了一个RMSAnalyzer类,你可以把他用在你的项目中来调试你的程序。

Record Store Discovery
你可以通过调用RecordStore.listRecordStores()来得到MIDlet suites中的Record Store,这个静态方法返回一个String类型的数组,每个代表Record Store的名字,如果没有record Store那么会返回null,方法RMSAnalyzer.annlyzeAll()通过调用listRecordStores()得到Record Store然后通过方法analyze()分析每个Record Store.

public void analyzeAll(){

String[] names = RecordStore.listRecordStores();

for( int i = 0;

names != null && i < names.length;

++i ){

analyze( names[i] );

}

}

注意到列出的数组名字是所属MIDlet suite的Record Store。MIDP中没有提供列举出任何其他MIDlet suites的Record Store的方法,在MIDP 1.0中Record Store在所属MIDlet suites外是不可见的,在MIDP 2.0中,MIDlet suite可以指定一个Record Store作为可共享的,但是其他的suite要知道他的名字才可以访问它。

Opening and closing Record Store
RecordStore.openRecordStore()是用来打开一个Record Store的,它也可以用来创建一个Record Store,这个静态方法返回一个Record Store的对象,下面是RMSAnalyzer.analyze()。

public void analyze( String rsName ){

RecordStore rs = null;

try {

rs = RecordStore.openRecordStore( rsName, false );

analyze( rs ); // call overloaded method

} catch( RecordStoreException e ){

logger.exception( rsName, e );

} finally {

try {

rs.closeRecordStore();

} catch( RecordStoreException e ){

// Ignore this exception

}

}

}

openRecordStore()的第二个参数表示如果record store不存在是不是创建新的,在MIDP2.0中,如果你想打开一个在其他的MIDlet suite里面创建的Record Store的话应该用下面的方法。

...

String name = "mySharedRS";

String vendor = "EricGiguere.com";

String suite = "TestSuite";

RecordStore rs =

RecordStore.openRecordStore( name, vendor, suite );

...

vendor和suite的名字应该和MIDlet suite的manifest和jad的内容一致。

当你完成了对record store的操作以后应该调用RecordStore.closeRecordStore()来关闭它,一个RecordStore的实例在一个MIDlet suite里面是唯一的,如果以同样的名字再次调用openRecordStore()的话会返回同样的实例,这样多个MIDlet在共享一个record store,每个record store会跟踪它被打开的次数,这个record store直到被调用相同次数的closeRecordStore()后才会彻底的关闭,对一个已经关闭的Record Store进行操作会导致抛出

RecordStoreNotOpenException。

Creating Record Store
创建一个私有的record store,把第二个参数设置为true调用openRecordStore(),...

// Create a record store

RecordStore rs = null;

try {

rs = RecordStore.openRecordStore( "myrs", true );

} catch( RecordStoreException e ){

// couldn't open it or create it

}

如果要创建一个可共享的record store,那么使用四个参数变量的openRecordStore()

int authMode = RecordStore.AUTHMODE_ANY;

boolean writable = true;

rs = RecordStore.openRecordStore( "myrs", true,

authMode, writable );

当第二个参数是true并且record store不存在的时候,后面两个参数控制他的授权模式和可写性,授权模式决定是否其他的MIDlet suite具有访问record store的权限,两种可能的模式是RecordStore.AUTHMODE_PRIVATE(只有拥有的SUITE才可以访问)和RecordStore.AUTHMODE_ANY(任何suite都可以访问),可写性控制着是否其他的suite能够修改record store,如果false的话,那么只有所属suite才可以修改,其他的只能读取。注意所属suite可以在任何时候调用RecordStore.setMode()来修改它的授权和读写模式,例如:

rs.setMode( RecordStore.AUTHMODE_ANY, false );事实上最好是创建一个record store,授权模式为RecordStore.AUTHMODE_PRIVATE。

Adding and updating records
记录就是字节数组,你可以通过调用RecordStore.addRecord()来添加一个新的记录到一个打开的Record Store

byte[] data = new byte[]{ 0, 1, 2, 3 };

int recordID;
recordID = rs.addRecord( data, 0, data.length );

如果第一个参数是null的话,那么你就能添加一个空记录。第二个和第三个参数说明了字节数组的起点和从起点开始的总的字节数。如果添加成功会返回新记录的record ID,如果失败会抛出异常,例如RecordStoreFullException。

通过调用RecordStore.setRecord()可以在任何时候更新记录的内容。

int recordID = ...; // some record ID

byte[] data = new byte[]{ 0, 10, 20, 30 };

rs.setRecord( recordID, data, 1, 2 );

// replaces all data in record with 10, 20

你不能大块的添加记录,必须首先把记录转换成数组,然后调用添加的函数,通过调用RecordStore.getNextRecordID()你可以得到下次调用addRecord()将要得到的record ID,这个值比现在使用的任何值都大。

Reading records
想要读取记录,有两种方法。第一是分配合适大小的数组然后把记录的内容复制过去。

int recordID = .... // some record ID

byte[] data = rs.getRecord( recordID );

第二种方法是把数组复制到预先分配的字节数组中,指定复制的起点并返回复制的字节数目。

int recordID = ...; // some record ID

byte[] data = ...; // an array

int offset = ...; // the starting offset

int numCopied = rs.getRecord( recordID, data, offset );

数组的大小必须能足够容纳数据,否则会抛出java.lang.ArrayIndexOutOfBoundsException.使用RecordStore.getRecordSize()来分配数组空间是合适的方法。事实上第一个方法等价与

byte[] data = new byte[rs.getRecordSize(recordID)];

rs.getRecord(recordID,data,0);

第二种方法有利于减小内存的分配,当你要遍历一组记录的时候,你可以结合getNextRecordID()和getRecordSize()来完成运算量很大的搜索。

int nextID = rs.getNextRecordID();

byte[] data = null;

for( int id = 0; id < nextID; ++id ){

try {

int size = rs.getRecordSize( id );

if( data == null || data.length < size ){

data = new byte[ size ];

}

rs.getRecord( id, data, 0 );

processRecord( rs, id, data, size ); // process it

} catch( InvalidRecordIDException e ){

// ignore, move to next record

} catch( RecordStoreException e ){

handleError( rs, id, e ); // call an error routine

}

}

更好的办法是使用RecordStore.enumerateRecords()来遍历记录。

Deleting Records and Record Stores
你可以通过调用RecordStore.deleteRecord()来删除记录

int recordID = ...; // some record ID

rs.deleteRecord( recordID );

一旦记录被删除,任何对记录的操作将会导致抛出InvalidRecordIDException,通过调用RecordStore.deleteRecordStore()来删除Record Store.

try {

RecordStore.deleteRecordStore( "myrs" );

} catch( RecordStoreNotFoundException e ){

// no such record store

} catch( RecordStoreException e ){

// somebody has it open

}

Record Store只能在没有打开的时候被所属的suite的MIDlet删除。

其他操作
getLastModified()返回最后修改record store的时间,格式和System.currentTimeMillis()一样。

getName()得到record store的名字。

getNumRecords()返回record store中记录的数量。

getSize()返回record store的整个大小,包括记录的大小和系统来实现record store的空间。

getSizeAvailable()返回record store中还能用的空间,

getVersion()返回record store的版本数,这个数大于0,每次record store被修改,这个数都会自动增加。

一个MIDlet能够通过注册一个监听器来跟踪record store,通过addRecordListener()和deleteRecordListener()。

The RMSAnalyzer class
最后我们提供一个分析record store的类,你可以这样使用它。

RecordStore rs = ...; // open the record store

RMSAnalyzer analyzer = new RMSAnalyzer();

analyzer.analyze( rs );

通常分析输出到System.out,样式如下所示:

=========================================

Record store: recordstore2

Number of records = 4

Total size = 304

Version = 4

Last modified = 1070745507485

Size available = 975950

Record #1 of length 56 bytes

5f 62 06 75 2e 6b 1c 42 58 3f _b.u.k.BX?

1e 2e 6a 24 74 29 7c 56 30 32 ..j$t)|V02

5f 67 5a 13 47 7a 77 68 7d 49 _gZ.Gzwh}I

50 74 50 20 6b 14 78 60 58 4b PtP k.x`XK

1a 61 67 20 53 65 0a 2f 23 2b .ag Se./#+

16 42 10 4e 37 6f .B.N7o

Record #2 of length 35 bytes

22 4b 19 22 15 7d 74 1f 65 26 "K.".}t.e&

4e 1e 50 62 50 6e 4f 47 6a 26 N.PbPnOGj&

31 11 74 36 7a 0a 33 51 61 0e 1.t6z.3Qa.

04 75 6a 2a 2a .uj**

Record #3 of length 5 bytes

47 04 43 22 1f G.C".

Record #4 of length 57 bytes

6b 6f 42 1d 5b 65 2f 72 0f 7a koB.[e/r.z

2a 6e 07 57 51 71 5f 68 4c 5c *n.WQq_hL\

1a 2a 44 7b 02 7d 19 73 4f 0b .*D{.}.sO.

75 03 34 58 17 19 5e 6a 5e 80 u.4X..^j^?

2a 39 28 5c 4a 4e 21 57 4d 75 *9(\JN!WMu

80 68 06 26 3b 77 33 ?h.&;w3

Actual size of records = 153

-----------------------------------------

这种样式方便在wtk中显示,在实际的设备中进行测试的时候,你可能希望把分析输出到串口或者通过网络发到servlet,你可以通过定义自己的类实现实现Logger接口,然后把这个类作为RMSAnalyzer构造器的参数。下面是源代码。

package com.ericgiguere;

import java.io.*;

import javax.microedition.rms.*;

// Analyzes the contents of a record store.

// By default prints the analysis to System.out,

// but you can change this by implementing your

// own Logger.

public class RMSAnalyzer {

// The logging interface.

public interface Logger {

void logEnd( RecordStore rs );

void logException( String name, Throwable e );

void logException( RecordStore rs, Throwable e );

void logRecord( RecordStore rs, int id,

byte[] data, int size );

void logStart( RecordStore rs );

}

private Logger logger;

// Constructs an analyzer that logs to System.out.

public RMSAnalyzer(){

this( null );

}

// Constructs an analyzer that logs to the given logger.

public RMSAnalyzer( Logger logger ){

this.logger = ( logger != null ) ? logger :

new SystemLogger();

}

// Open the record stores owned by this MIDlet suite

// and analyze their contents.

public void analyzeAll(){

String[] names = RecordStore.listRecordStores();

for( int i = 0;

names != null && i < names.length;

++i ){

analyze( names[i] );

}

}

// Open a record store by name and analyze its contents.

public void analyze( String rsName ){

RecordStore rs = null;

try {

rs = RecordStore.openRecordStore( rsName, false );

analyze( rs );

} catch( RecordStoreException e ){

logger.logException( rsName, e );

} finally {

try {

rs.closeRecordStore();

} catch( RecordStoreException e ){

// Ignore this exception

}

}

}

// Analyze the contents of an open record store using

// a simple brute force search through the record store.

public synchronized void analyze( RecordStore rs ){

try {

logger.logStart( rs );

int lastID = rs.getNextRecordID();

int numRecords = rs.getNumRecords();

int count = 0;

byte[] data = null;

for( int id = 0;

id < lastID && count < numRecords;

++id ){

try {

int size = rs.getRecordSize( id );

// Make sure data array is big enough,

// plus add some for growth

if( data == null || data.length < size ){

data = new byte[ size + 20 ];

}

rs.getRecord( id, data, 0 );

logger.logRecord( rs, id, data, size );

++count; // only increase if record exists

}

catch( InvalidRecordIDException e ){

// just ignore and move to the next one

}

catch( RecordStoreException e ){

logger.logException( rs, e );

}

}

} catch( RecordStoreException e ){

logger.logException( rs, e );

} finally {

logger.logEnd( rs );

}

}

// A logger that outputs to a PrintStream.

public static class PrintStreamLogger implements Logger {

public static final int COLS_MIN = 10;

public static final int COLS_DEFAULT = 20;

private intcols;

private intnumBytes;

private StringBuffer hBuf;

private StringBuffer cBuf;

private StringBuffer pBuf;

private PrintStream out;

public PrintStreamLogger( PrintStream out ){

this( out, COLS_DEFAULT );

}

public PrintStreamLogger( PrintStream out, int cols ){

this.out = out;

this.cols = ( cols > COLS_MIN ? cols : COLS_MIN );

}

private char convertChar( char ch ){

if( ch < 0x20 ) return '.';

return ch;

}

public void logEnd( RecordStore rs ){

out.println( "\nActual size of records = "

+ numBytes );

printChar( '-', cols * 4 + 1 );

hBuf = null;

cBuf = null;

pBuf = null;

}

public void logException( String name, Throwable e ){

out.println( "Exception while analyzing " +

name + ": " + e );

}

public void logException( RecordStore rs, Throwable e ){

String name;

try {

name = rs.getName();

} catch( RecordStoreException rse ){

name = "";

}

logException( name, e );

}

public void logRecord( RecordStore rs, int id,

byte[] data, int len ){

if( len < 0 && data != null ){

len = data.length;

}

hBuf.setLength( 0 );

cBuf.setLength( 0 );

numBytes += len;

out.println( "Record #" + id + " of length "

+ len + " bytes" );

for( int i = 0; i < len; ++i ){

int b = Math.abs( data[i] );

String hStr = Integer.toHexString( b );

if( b < 0x10 ){

hBuf.append( '0');

}

hBuf.append( hStr );

hBuf.append( ' ' );

cBuf.append( convertChar( (char) b ) );

if( cBuf.length() == cols ){

out.println( hBuf + " " + cBuf );

hBuf.setLength( 0 );

cBuf.setLength( 0 );

}

}

len = cBuf.length();

if( len > 0 ){

while( len++ < cols ){

hBuf.append( " " );

cBuf.append( ' ' );

}

out.println( hBuf + " " + cBuf );

}

}

public void logStart( RecordStore rs ){

hBuf = new StringBuffer( cols * 3 );

cBuf = new StringBuffer( cols );

pBuf = new StringBuffer();

printChar( '=', cols * 4 + 1 );

numBytes = 0;

try {

out.println( "Record store: "

+ rs.getName() );

out.println( " Number of records = "

+ rs.getNumRecords() );

out.println( " Total size = "

+ rs.getSize() );

out.println( " Version = "

+ rs.getVersion() );

out.println( " Last modified = "

+ rs.getLastModified() );

out.println( " Size available = "

+ rs.getSizeAvailable() );

out.println( "" );

} catch( RecordStoreException e ){

logException( rs, e );

}

}

private void printChar( char ch, int num ){

pBuf.setLength( 0 );

while( num-- > 0 ){

pBuf.append( ch );

}

out.println( pBuf.toString() );

}

}

// A logger that outputs to System.out.

public static class SystemLogger extends PrintStreamLogger
{

public SystemLogger(){

super( System.out );

}

public SystemLogger( int cols ){

super( System.out, cols );

}

}

分享到:
评论

相关推荐

    J2ME从入门到精通

    **J2ME从入门到精通** Java Micro Edition(J2ME)是Java平台的一个子集,主要用于嵌入式系统和移动设备,如早期的智能手机、电视盒和家用电器。本教程将带你逐步深入J2ME的世界,理解其基本概念、开发环境搭建、...

    j2me程序开发实用案例从入门到精通

    《J2ME程序开发实用案例从入门到精通》是一本专为Java初学者和开发者设计的教程,旨在帮助读者深入理解和掌握J2ME(Java 2 Micro Edition)平台的编程技术。J2ME是Java技术在移动设备和嵌入式系统上的应用版本,广泛...

    J2ME实用教程:从入门到精通的所有ppt

    在《J2ME实用教程:从入门到精通的所有ppt》中,你可以期待学习以下关键知识点: 1. **J2ME架构**:了解CLDC(Connected Limited Device Configuration)和MIDP(Mobile Information Device Profile)是如何构成...

    ZEMAX光学设计软件 学习手册

    1. **广泛的适用范围**:ZEMAX支持多种类型的光学系统设计,从简单的单透镜到复杂的多元件系统均可处理。 2. **强大的功能集**:软件提供了丰富的工具和功能,如光线追踪、优化算法、数据分析等,帮助用户高效地完成...

    精通J2ME无线编程

    3. **MIDP**:Mobile Information Device Profile是J2ME上的应用开发接口,包含了用户界面组件(如Canvas和Form)、网络访问能力以及数据存储机制,如Record Management System (RMS)。 4. **Wireless Toolkit**:...

    J2ME手机开发入门知识必读

    3. RMS:Record Management System,用于在设备上存储数据。 七、网络通信 MIDP提供了HttpConnection和SocketConnection接口,可用于发送HTTP请求和建立TCP连接,实现网络通信功能。 八、图形和多媒体 MIDP支持...

    J2ME程序开发新手入门九大要点

    3. J2ME游戏移植人员:将游戏从一个平台移植到另一个平台,要求了解不同平台的技术规格和差异。 五、J2ME程序设计原则 1. 面向对象编程:即便可能导致文件大小增加,也应优先选择面向对象编程,以便于代码的维护和...

    ArcGIS基本操作教程大全

    通过上述知识点的介绍和操作演示,该教程旨在为用户提供一套全面、实用的ArcGIS学习资源,帮助用户从入门到精通,全面掌握ArcGIS软件的使用技巧和各种功能。需要强调的是,教程的每个部分都有可能结合具体的操作界面...

    j2me撞砖游戏

    《J2ME撞砖游戏详解:入门到精通》 J2ME(Java 2 Micro Edition)是Java平台的一个重要分支,主要用于开发移动设备、嵌入式系统等小型应用,其中包括了我们今天要讨论的“撞砖游戏”。这款游戏简单易懂,非常适合...

    PDF-BeginningJavaMEPlatformPDFBooks-英文版.rar

    这本书的英文版详细介绍了如何使用Java ME进行移动应用开发,涵盖了从基础知识到实际应用的各个方面。以下是一些主要的知识点: 1. **Java ME简介**:介绍Java ME的历史、目标和适用场景,解释为什么它是开发嵌入式...

    J2me开发须知

    3. **J2ME游戏移植人员**:将游戏从一个平台移植到另一个平台,需要了解平台差异和技术参数。 **五、J2ME程序设计原则** 1. **面向对象编程**:即使牺牲一些体积,也要保持代码的可维护性和可扩展性。 2. **MVC...

    J2ME 手机程序开发

    ### 第一章:J2ME入门 1. **J2ME体系结构**:J2ME由几个关键组件构成,包括Connected Limited Device Configuration (CLDC)和Connected Device Configuration (CDC)。CLDC适用于内存和处理能力有限的设备,如基本...

    J2ME程序开发全方位基础讲解汇总

    本教程将全方位地讲解J2ME程序开发的基础知识,帮助开发者入门并掌握其核心概念。 1. **J2ME架构** J2ME由配置(Configurations)和 profiles 组成。配置定义了硬件和操作系统的最小要求,如MIDP(Mobile ...

Global site tag (gtag.js) - Google Analytics