`
mylftnt
  • 浏览: 26990 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

数据库和 MIDP

 
阅读更多
数据库和 MIDP,第三部分:使用数据映射

本系列中的 第二部分介绍了数据映射的基本知识。您学会了如何在字节数组(byte array)中存储原始数据类型的数值,如何使用流向记录库(recordstore)中存储对象和从记录库中检索对象以及如何从字节数组中抽取已存储的数值。在本文中,您将学会如何使您的应用程序远离这些低级操作,方法是对核心类进行扩展使其包含读写操作,创建并使用字段列表来存储和检索对象。

扩展核心类

J2ME 开发人员的目标之一是最小化应用程序对内存的使用。理想情况下,在任何给定的时间内,内存中应该只含有某个数据块的一个副本。然而,当您向 ByteArrayOutputStream 写数据时,您从来无法访问其基本的字节数组--调用toByteArray() 返回该数组的一个拷贝。如果您紧接着就将该字节数组保存到记录库中,则会造成没必要的内存浪费。要直接访问该数组,只需要对类ByteArrayOutputStream 进行简单的扩展即可,扩展后的类称为DirectByteArrayOutputStream

package j2me.io;

import java.io.*;

// A version of ByteArrayOutputStream that gives you
// direct access to the underlying byte array if
// you need it.

public class DirectByteArrayOutputStream 
                       extends ByteArrayOutputStream {

    // Constructs a byte array output stream of default size

    public DirectByteArrayOutputStream(){
        super();
    }

    // Constructs a byte array output stream of given size

    public DirectByteArrayOutputStream( int size ){
        super( size );
    }

    // Returns a reference to the underlying byte array.
    // The actual amount of data in the byte array is
    // obtained via the size method.

    public synchronized byte[] getByteArray(){
        return buf;
    }

    // Swaps in a new byte array for the old one, resetting
    // the count as well.

    public synchronized byte[] swap( byte[] newBuf ){
        byte[] oldBuf = buf;
        buf = newBuf;
        reset();
        return oldBuf;
    }
}

记住调用 size() 方法查看存储在字节数组中的实际数据的多少:

...
DirectByteArrayOutputStream bout = ... 
RecordStore rs = ...

int numBytes = bout.size();
byte[] data = bout.getByteArray();

rs.addRecord( data, 0, numBytes );
...

未来保持一致性,您可以用类似的方法对 ByteArrayInputStream 类进行扩展:

package j2me.io;

import java.io.*;

// A version of ByteArrayInputStream that lets you
// replace the underlying byte array.

public class DirectByteArrayInputStream 
                  extends ByteArrayInputStream {

    // Constructs an output stream from the given array

    public DirectByteArrayInputStream( byte buf[] ){
        super( buf );
    }

    // Constructs an output stream from the given subarray

    public DirectByteArrayInputStream( byte buf[],
                                       int offset, 
                                       int length ){
        super( buf, offset, length );
    }

    // Resets the array the stream reads from

    public synchronized void setByteArray( byte[] buf ){
        this.buf = buf;
        this.pos = 0;
        this.count = buf.length;
        this.mark = 0;
    }

    // Resets the array the stream reads from

    public synchronized void setByteArray( byte[] buf, 
                                           int offset,
                                           int length ){
        this.buf = buf;
        this.pos = offset;
        this.count = Math.min( offset + length, buf.length );
        this.mark = offset;
    }
}

注意类ByteArrayInputStream和类ByteArrayOutputStream以及以上所写的两个扩展类都使用了用于线程安全的同步方法。尽管在大多数情况下只有单一线程使用这些流,同步也就没有必要了。如果您的应用程序需要读写大量的数据,可考虑创建基于这些类的非同步的版本以获得较快的速度。

您也可以很容易的对 DataInputStreamDataOutputStream 进行扩展。例如,如果您需要在多个地方写整型数组,请使用DataOutputStream 的以下扩展:

package j2me.io;

import java.io.*;

public class ExtendedDataOutputStream extends DataOutputStream {
    public ExtendedDataOutputStream( OutputStream out ){
        super( out );
    }

    public final void writeIntArray( int[] arr ) 
                                     throws IOException {
        int size = arr.length;
        writeInt( size );
        for( int i = 0; i < size; ++i ){
            writeInt( arr[i] );
        }
    }
}

相反,您可以将这种代码放入一个帮助器类,因为您不需要访问任何的 protected members。

创建记录字段

现在您已经拥有了创建基于字段的记录库的所有工具,记录库中的每条记录都是一组指定类型的命名字段。您利用两个类来管理该记录库。其中的第一个类 FieldList管理字段自身的信息--元数据:

package j2me.rms;

import java.io.*;
import javax.microedition.rms.*;

// Maintains information about the fields in a
// field-based record store. Currently just a list of
// field types and (optional) field names, but could
// easily be expanded to store other information.

public class FieldList {

    private static final int VERSION = 1;

    // The basic field types.

    public static final byte TYPE_BOOLEAN = 1;
    public static final byte TYPE_BYTE = 2;
    public static final byte TYPE_CHAR = 3;
    public static final byte TYPE_SHORT = 4;
    public static final byte TYPE_INT = 5;
    public static final byte TYPE_LONG = 6;
    public static final byte TYPE_STRING = 7;

    // Constructs an empty list.

    public FieldList(){
    }

    // Constructs a list of the given size.

    public FieldList( int numFields ){
        if( numFields < 0 || numFields > 255 ){
            throw new IllegalArgumentException( 
                       "Bad number of fields" );
        }

        _types = new byte[ numFields ];
        _names = new String[ numFields ];
    }

    // Returns the number of fields.

    public int getFieldCount(){
        return _types != null ? _types.length : 0;
    }

    // Returns the name of a field.

    public String getFieldName( int index ){
        String name = _names[ index ];
        return name != null ? name : "";
    }

    // Returns the type of a field.

    public byte getFieldType( int index ){
        return _types[ index ];
    }

    // Reads the field list from a byte array.

    public void fromByteArray( byte[] data )
                               throws IOException {
        ByteArrayInputStream bin = 
                  new ByteArrayInputStream( data );
        fromDataStream( new DataInputStream( bin ) );
        bin.close();
    }

    // Reads the fields list from a data stream.

    public void fromDataStream( DataInputStream din )
                                throws IOException {
        int version = din.readUnsignedByte();
        if( version != VERSION ){
            throw new IOException( "Incorrect version " +
                  version + " for FieldList, expected " +
                  VERSION );
        }

        int numFields = din.readUnsignedByte();

        _types = new byte[ numFields ];
        _names = new String[ numFields ];

        if( numFields > 0 ){
            din.readFully( _types );
    
            for( int i = 0; i < numFields; ++i ){
                _names[i] = din.readUTF();
            }
        }
    }

    // Reads a field list from a record store.

    public void fromRecordStore( RecordStore rs, int index )
                                 throws IOException, 
                                        RecordStoreException {
        fromByteArray( rs.getRecord( index ) );
    }

    // Sets the name of a field.

    public void setFieldName( int index, String name ){
        _names[ index ] = name;
    }

    // Sets the type of a field.

    public void setFieldType( int index, byte type ){
        _types[ index ] = type;
    }

    // Stores the fields list to a byte array

    public byte[] toByteArray() throws IOException {
        ByteArrayOutputStream bout = 
                     new ByteArrayOutputStream();
        toDataStream( new DataOutputStream( bout ) );
        byte[] data = bout.toByteArray();
        bout.close();
        return data;
    }

    // Stores the fields list to a data stream

    public void toDataStream( DataOutputStream out )
                              throws IOException {
        out.writeByte( VERSION );

        int count = getFieldCount();

        out.writeByte( count );

        if( count > 0 ){
            out.write( _types, 0, count );

            for( int i = 0; i < count; ++i ){
                out.writeUTF( getFieldName( i ) );
            }
        }
    }

    // Writes a field list to a record store.

    public int toRecordStore( RecordStore rs, int index )
                               throws IOException, 
                                      RecordStoreException {
        byte[]  data = toByteArray();
        boolean add = true;

        if( index > 0 ){
            try {
                rs.setRecord( index, data, 0, data.length );
                add = false;
            }
            catch( InvalidRecordIDException e ){
            }
        }

        // If the record doesn't actually exist yet,
        // go ahead and create it by inserting dummy
        // records ahead of it

        if( add ){
            synchronized( rs ){
                int nextID = rs.getNextRecordID();
                if( index <= 0 ) index = nextID;
    
                while( nextID < index ){
                    rs.addRecord( null, 0, 0 );
                }
    
                if( nextID == index ){
                    rs.addRecord( data, 0, data.length );
                }
            }
        }

        return index;
    }

    private String[] _names;
    private byte[]   _types;
}

实际上,一个 FieldList 实例只是两个数组的一个包装器。

在其核心,一个 FieldList 实例只是两个数组的一个包装器。第一个数组存储每个字段的类型,第二个数组存储每个字段的名称。名称是可选的,重要的是类型,因为它决定如何将数据写入记录和从记录中读出。所有标准的 Java 原始数据类型都支持,还有String 类型。下面是对存储某个组织的部门列表的字段的定义:

...
FieldList depts = new FieldList( 3 );
depts.setFieldType( 0, FieldList.TYPE_SHORT );
depts.setFieldName( 0, "ID" );
depts.setFieldType( 1, FieldList.TYPE_STRING );
depts.setFieldName( 1, "Name" );
depts.setFieldType( 2, FieldList.TYPE_INT );
depts.setFieldName( 2, "ManagerID" );
...

一个 FieldList

实例可存储在一个数据流、一个字节数组或者一个记录库中。如果您将字段列表存储为记录库中的第一条记录,则任何可打开该记录库的代码就可以读取该记录以决定其余字段的字段布局。要使这个策略起到作用,您必须在创建记录库后立即存储记录列表:

...
FieldList list = ... // a field list
RecordStore rs = RecordStore.openRecordStore( "foo", true );
if( rs.getNumRecords() == 0 ){ // empty, store it
    list.toRecordStore( rs, -1 );
}
...

toRecordStore() 方法的第二个参数确定了保存字段数据所使用的记录。负值表示将要添加一条新的记录。

管理基于字段的记录库所需的第二个类是 FieldBasedStore,它将管理实际的读写操作:

package j2me.rms;

import java.io.*;
import javax.microedition.rms.*;
import j2me.io.*;

// A wrapper class for a record store that allows the
// records to be accessed as a set of fields. The field
// definitions are maintained separately using a FieldList
// object, which can be stored as part of the record store
// or separately.

public class FieldBasedStore {

    // Some useful constants

    public static Boolean TRUE = new Boolean( true );
    public static Boolean FALSE = new Boolean( false );

    // Markers for the types of string we support

    private static final byte NULL_STRING_MARKER = 0;
    private static final byte UTF_STRING_MARKER = 1;

    // Constructs a field store where the field list is
    // assumed to be stored in the first record.

    public FieldBasedStore( RecordStore rs )
                            throws IOException,
                                   RecordStoreException {
        this( rs, 1 );
    }

    // Constructs a field store where the field list is
    // stored in the given record.

    public FieldBasedStore( RecordStore rs, int fieldListID )
                            throws IOException,
                                   RecordStoreException {
        this( rs, loadFieldList( rs, fieldListID ) );
    }

    // Constructs a field store with the given field list.

    public FieldBasedStore( RecordStore rs, FieldList list ){
        _rs = rs;
        _fieldList = list;
    }

    // Adds a new record to the store. Returns the new
    // record ID.

    public synchronized int addRecord( Object[] fields )
                                 throws IOException,
                                        RecordStoreException {
        writeStream( fields );
        byte[] data = _bout.getByteArray();
        return _rs.addRecord( data, 0, data.length );
    }

    // Returns the current field list.

    public FieldList getFieldList(){
        return _fieldList;
    }

    // Returns the record store.

    public RecordStore getRecordStore(){
        return _rs;
    }

    // Loads the field list from the record store.

    private static FieldList loadFieldList( RecordStore rs,
                                            int fieldListID )
                                 throws IOException,
                                        RecordStoreException {
        FieldList list = new FieldList();
        list.fromRecordStore( rs, fieldListID );
        return list;
    }

    // Prepares the store for input by making sure that
    // the data buffer is big enough. The streams are
    // reused.

    private void prepareForInput( int size ){
        if( _buffer == null || _buffer.length < size ){
            _buffer = new byte[ size ];
        }

        if( _bin == null ){
            _bin = new DirectByteArrayInputStream( _buffer );
            _din = new DataInputStream( _bin );
        } else {
            _bin.setByteArray( _buffer );
        }
    }

    // Prepares the store for output. The streams are reused.

    private void prepareForOutput(){
        if( _bout == null ){
            _bout = new DirectByteArrayOutputStream();
            _dout = new DataOutputStream( _bout );
        } else {
            _bout.reset();
        }
    }

    // Reads a field from the buffer.

    private Object readField( int type ) throws IOException {
        switch( type ){
            case FieldList.TYPE_BOOLEAN:
                return _din.readBoolean() ? TRUE : FALSE;
            case FieldList.TYPE_BYTE:
                return new Byte( _din.readByte() );
            case FieldList.TYPE_CHAR:
                return new Character( _din.readChar() );
            case FieldList.TYPE_SHORT:
                return new Short( _din.readShort() );
            case FieldList.TYPE_INT:
                return new Integer( _din.readInt() );
            case FieldList.TYPE_LONG:
                return new Long( _din.readLong() );
            case FieldList.TYPE_STRING: {
                byte marker = _din.readByte();
                if( marker == UTF_STRING_MARKER ){
                    return _din.readUTF();
                }
            }
        }

        return null;
    }

    // Reads the record at the given ID and returns it as
    // a set of objects that match the types in the 
    // field list.

    public synchronized Object[] readRecord( int recordID )
                                 throws IOException,
                                        RecordStoreException {
        prepareForInput( _rs.getRecordSize( recordID ) );
        _rs.getRecord( recordID, _buffer, 0 );

        int count = _fieldList.getFieldCount();
        Object[] fields = new Object[ count ];

        for( int i = 0; i < count; ++i ){
            fields[i] = readField(_fieldList.getFieldType(i));
        }

        return fields;
    }

    // Converts an object to a boolean value.

    public static boolean toBoolean( Object value ){
        if( value instanceof Boolean ){
            return ((Boolean) value).booleanValue();
        } else if( value != null ){
            String str = value.toString().trim();

            if( str.equals( "true" ) ) return true;
            if( str.equals( "false" ) ) return false;

            return( toInt( value ) != 0 );
        }

        return false;
    }

    // Converts an object to a char.

    public static char toChar( Object value ){
        if( value instanceof Character ){
            return ((Character) value).charValue();
        } else if( value != null ){
            String s = value.toString();
            if( s.length() > 0 ){
                return s.charAt( 0 );
            }
        }

        return 0;
    }

    // Converts an object to an int. This code
    // would be much simpler if the CLDC supported
    // the java.lang.Number class.

    public static int toInt( Object value ){
        if( value instanceof Integer ){
            return ((Integer) value).intValue();
        } else if( value instanceof Boolean ){
            return ((Boolean) value).booleanValue() ? 1 : 0;
        } else if( value instanceof Byte ){
            return ((Byte) value).byteValue();
        } else if( value instanceof Character ){
            return ((Character) value).charValue();
        } else if( value instanceof Short ){
            return ((Short) value).shortValue();
        } else if( value instanceof Long ){
            return (int) ((Long) value).longValue();
        } else if( value != null ){
            try {
                return Integer.parseInt( value.toString() );
            }
            catch( NumberFormatException e ){
            }
        }

        return 0;
    }

    // Converts an object to a long. This code
    // would be much simpler if the CLDC supported
    // the java.lang.Number class.

    public static long toLong( Object value ){
        if( value instanceof Integer ){
            return ((Integer) value).longValue();
        } else if( value instanceof Boolean ){
            return ((Boolean) value).booleanValue() ? 1 : 0;
        } else if( value instanceof Byte ){
            return ((Byte) value).byteValue();
        } else if( value instanceof Character ){
            return ((Character) value).charValue();
        } else if( value instanceof Short ){
            return ((Short) value).shortValue();
        } else if( value instanceof Long ){
            return ((Long) value).longValue();
        } else if( value != null ){
            try {
                return Long.parseLong( value.toString() );
            }
            catch( NumberFormatException e ){
            }
        }

        return 0;
    }

    // Writes a field to the output buffer.

    private void writeField( int type, Object value )
                                 throws IOException {
        switch( type ){
            case FieldList.TYPE_BOOLEAN:
                _dout.writeBoolean( toBoolean( value ) );
                break;
            case FieldList.TYPE_BYTE:
                _dout.write( (byte) toInt( value ) );
                break;
            case FieldList.TYPE_CHAR:
                _dout.writeChar( toChar( value ) );
                break;
            case FieldList.TYPE_SHORT:
                _dout.writeShort( (short) toInt( value ) );
                break;
            case FieldList.TYPE_INT:
                _dout.writeInt( toInt( value ) );
                break;
            case FieldList.TYPE_LONG:
                _dout.writeLong( toLong( value ) );
                break;
            case FieldList.TYPE_STRING:
                if( value != null ){
                    String str = value.toString();
                    _dout.writeByte( UTF_STRING_MARKER );
                    _dout.writeUTF( str );
                } else {
                    _dout.writeByte( NULL_STRING_MARKER );
                }
                break;
        }
    }

    // Writes a set of fields to the given record. The
    // fields must be compatible with the types in
    // the field list.

    public synchronized void writeRecord( int recordID,
                                          Object[] fields )
                                 throws IOException,
                                        RecordStoreException {
        writeStream( fields );
        byte[] data = _bout.getByteArray();
        _rs.setRecord( recordID, data, 0, data.length );
    }

    // Writes a set of fields to the output stream.

    private void writeStream( Object[] fields )
                                       throws IOException {
        int count = _fieldList.getFieldCount();
        int len = ( fields != null ? fields.length : 0 );

        prepareForOutput();

        for( int i = 0; i < count; ++i ){
            writeField( _fieldList.getFieldType( i ),
                        ( i < len ? fields[i] : null ) );
        }
    }

    private DirectByteArrayInputStream  _bin;
    private DirectByteArrayOutputStream _bout;
    private byte[]                      _buffer;
    private DataInputStream             _din;
    private DataOutputStream            _dout;
    private FieldList                   _fieldList;
    private RecordStore                 _rs;
}

要创建一个 FieldBasedStore,你需要一个RecordStore 实例和一个FieldList 实例。您可以在构造FieldBasedStore 的过程中隐式地从记录库自身中读取后者:

...
RecordStore rs = ... // an open record store
FieldBasedStore fstore = new FieldBasedStore( rs );
...

或者您可以对其进行显式指定:

...
RecordStore rs = ... // an open record store
FieldList list = ... // a field list
FieldBasedStore fstore = new FieldBasedStore( rs, list );
...

FieldBasedStore 将每条记录作为一个对象数组来处理。数组中的数据类型和字段列表中所描述的字段类型相匹配。在上面的部门列表中,每一个都含有一个部门标识符、一个部门名称以及一个经理标识符。您可以用如下方法添加一条记录:

...
Object[] fields = new Object[]{
    new Short( 1 ), "Accounting", new Integer( 100 )
};

int recordID = fstore.addRecord( fields );
...

注意 FieldBasedStore 中的写记录代码是具有智能性的,它可以执行“明显的”数据转换,所以您也可以用以下方法进行:

...
Object[] fields = new Object[]{ "1", "Accounting", "100" };
int recordID = fstore.addRecord( fields );
...

读取记录也同样简单:

...
Object[] fields = fstore.readRecord( recordID );
for( int i = 0; i < fields.length; ++i ){
    System.out.println( "Field: " +
       fstore.getFieldList().getFieldName( i ) +
       " Value: " + fields[i] );
}
...

您可以在任何时候重写该数组来修改记录:

...
Object[] fields = fstore.readRecord( recordID );
fields[2] = "134"; // change the manager
fstore.writeRecord( recordID, fields );
...

这里有一个 MIDlet 的示例,它使用了一对基于字段的记录库来存储和检索雇员和部门数据。它也可使用 第一部分 所述的 RMSAnalyzer 类将记录库中的内容倒出,只是向您表明记录是如何被存储的。

import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.rms.*;
import j2me.rms.*;

// A simple MIDlet for testing RMS mappings
// done using the FieldBasedStore class.

public class RMSMappings extends MIDlet
                 implements CommandListener {

    private Display    display;

    public static final Command exitCommand =
                         new Command( "Exit",
                                      Command.EXIT, 1 ); 
    public static final Command testCommand =
                         new Command( "Test",
                                      Command.SCREEN, 1 );

    private static Object[][] empList = {
        new Object[]{ "1", "Mary", "CEO", "100", "F" },
        new Object[]{ "2", "John", "CFO", "200", "M" },
        new Object[]{ "3", "Pat", "Closem", "300", "F" },
        new Object[]{ "4", "PJ", "Admin", "100", "M" },
    };

    private static Object[][] deptList = {
        new Object[]{ "100", "Executive", "1" },
        new Object[]{ "200", "Operations", "2" },
        new Object[]{ "300", "Sales", "1" },
    };

    public RMSMappings(){
    }

    public void commandAction( Command c,
                               Displayable d ){
        if( c == exitCommand ){
            exitMIDlet();
        } else if( c == testCommand ){
            runTest();
        }
    }

    protected void destroyApp( boolean unconditional )
                       throws MIDletStateChangeException {
        exitMIDlet();
    }

    public void exitMIDlet(){
        notifyDestroyed();
    }

    public Display getDisplay(){ return display; }

    protected void initMIDlet(){
        display.setCurrent( new MainForm() );
    }

    protected void pauseApp(){
    }

    private void printRecord( FieldBasedStore store,
                              int recordID ){
        try {
            FieldList list = store.getFieldList();
            Object[]  fields = store.readRecord( recordID );

            if( fields.length != list.getFieldCount() ){
                System.out.println( "Error: bad count" );
                return;
            }

            System.out.println( "Record " + recordID + ":" );

            for( int i = 0; i < fields.length; ++i ){
                System.out.println( "  " +
                      list.getFieldName( i ) + ": " +
                      fields[i] );
            }
        }
        catch( RecordStoreException e  ){
        }
        catch( IOException e ){
        }
    }

    private void runTest(){
        // First delete the record stores...

        System.out.println( "Deleting record stores..." );

        String[] names = RecordStore.listRecordStores();

        for( int i = 0; i < names.length; ++i ){
            try {
                RecordStore.deleteRecordStore( names[i] );
            } catch( RecordStoreException e ){
                System.out.println( "Could not delete " +
                                    names[i] );
            }
        }

        // Create two record stores, one with a field list
        // stored in the first record and the second with
        // a field list stored separately (in the app)

        RecordStore     empRS = null;
        RecordStore     deptRS = null;
        FieldList       empFields = new FieldList( 5 );
        FieldList       deptFields = new FieldList( 3 );
        FieldBasedStore employees;
        FieldBasedStore departments;

        empFields.setFieldType( 0, FieldList.TYPE_INT );
        empFields.setFieldName( 0, "ID" );
        empFields.setFieldType( 1, FieldList.TYPE_STRING );
        empFields.setFieldName( 1, "Given Name" );
        empFields.setFieldType( 2, FieldList.TYPE_STRING );
        empFields.setFieldName( 2, "Last Name" );
        empFields.setFieldType( 3, FieldList.TYPE_BOOLEAN );
        empFields.setFieldName( 3, "Active" );
        empFields.setFieldType( 4, FieldList.TYPE_CHAR );
        empFields.setFieldName( 4, "Sex" );

        System.out.println( "Initializing employees" );

        try {
            empRS = RecordStore.openRecordStore( "empRS",
                                                 true );
            // now store the field list in the RS
            empFields.toRecordStore( empRS, -1 );
            employees = new FieldBasedStore( empRS );
        }
        catch( RecordStoreException e ){
            System.out.println( "Could not create empRS" );
            return;
        }
        catch( IOException e ){
            System.out.println( "Error storing field list" );
            return;
        }

        System.out.println( "Initializing departments" );

        deptFields.setFieldType( 0, FieldList.TYPE_INT );
        deptFields.setFieldName( 0, "ID" );
        deptFields.setFieldType( 1, FieldList.TYPE_STRING );
        deptFields.setFieldName( 1, "Name" );
        deptFields.setFieldType( 2, FieldList.TYPE_INT );
        deptFields.setFieldName( 2, "Manager" );

        try {
            deptRS = RecordStore.openRecordStore( "deptRS",
                                                  true );
            departments = new FieldBasedStore( deptRS,
                                               deptFields );
        }
        catch( RecordStoreException e ){
            System.out.println( "Could not create deptRS" );
            return;
        }

        int[] empRecordID;
        int[] deptRecordID;
        int   i;

        // Add the data...

        try {
            empRecordID = new int[ empList.length ];

            for( i = 0; i < empList.length; ++i ){
                empRecordID[i] =
                       employees.addRecord( empList[i] );
            }

            deptRecordID = new int[ deptList.length ];

            for( i = 0; i < deptList.length; ++i ){
                deptRecordID[i] =
                    departments.addRecord( deptList[i] );
            }
        }
        catch( RecordStoreException e ){
            System.out.println( "Error adding record" );
            return;
        }
        catch( IOException e ){
            System.out.println( "Error writing field" );
            return;
        }

        // Now fetch the data back and print it...

        System.out.println( "---- Employee data ----" );

        for( i = 0; i < empRecordID.length; ++i ){
            printRecord( employees, empRecordID[i] );
        }

        System.out.println( "---- Department data ----" );
    
        for( i = 0; i < deptRecordID.length; ++i ){
            printRecord( departments, deptRecordID[i] );
        }
    
        System.out.println( "Closing empRS" );

        try {
            empRS.closeRecordStore();
        }
        catch( RecordStoreException e ){
            System.out.println( "Error closing empRS" );
        }

        System.out.println( "Closing deptRS" );

        try {
            deptRS.closeRecordStore();
        }
        catch( RecordStoreException e ){
            System.out.println( "Error closing deptRS" );
        }

        System.out.println( "Dumping record stores..." );

        // Analyze them...

        RMSAnalyzer analyzer = new RMSAnalyzer(
                      new RMSAnalyzer.SystemLogger( 10 ) );
        analyzer.analyzeAll();
    }

    protected void startApp()
                      throws MIDletStateChangeException {
        if( display == null ){ 
            display = Display.getDisplay( this );
            initMIDlet();
        }
    }

    public class MainForm extends Form {
        public MainForm(){
            super( "RMSMappings" );

            addCommand( exitCommand );
            addCommand( testCommand );

            setCommandListener( RMSMappings.this );
        }
    }
}

正如它们现在所表明的,FieldBasedStoreFieldList类可以使用一些改善。例如,基于字段的库也可以基于游标,像一个 JDBC结果集,并使您在记录之间移动并抽取单个字段值。记录库可以缓冲记录。字段列表可以返回给定名称的字段的索引。当然,这些和其他的改进都是有同样代价的,于是您不得不在需要什么和什么会在您的平台上起作用之间进行平衡。当您预先不知道数据结构时,一个通用的基于字段的方法是最合适的。当然,预先不知道数据结构的情况并不常出现。通常,最好的方案是在一个持久存储对象中封装已知的对象类型。我在这里提出通用的方法,主要是告诉您最多能做些什么。

下一部分提要

第四节将讨论使用 RMS 的更高级的方面:遍历记录库和筛选记录。


分享到:
评论

相关推荐

    手机开发 rms 数据库管理

    作为 J2ME 101 教程系列的补充系列两篇文章中的第一篇,本文将向您介绍 MIDP 持久存储系统的内部工作原理。

    J2ME手机移动无线开发最新开发包 WTK Java(TM) Wireless Toolkit 2.5

     WTK是用来开发MIDP的,为了让MIDlet可以顺利编译和执行,WTK必须具有CLDC和MIDP的类库,WTK可以帮助我们省去额外安装调试这些类库的时间。而不同版本的WTK包含的程序库内容是不一样的,比如说2.0中包含了midpapi....

    J2ME 中文版教程

    这一特别的小型数据库使得MIDP 的数据保存变得很特 别。 第六章“GAME API” 介绍了MIDP 2.0 相对于1.0 来说,最大的变化——新添加的用于支 持游戏的API,它们被放在javax.microedition.lcdui.game 包中。游戏API ...

    J2ME 中文教程

    这一特别的小型数据库使得MIDP的数据保存变得很特别。 第六章“GAME API” 介绍了MIDP 2.0相对于1.0来说,最大的变化——新添加的用于支持游戏的API,它们被放在javax.microedition.lcdui.game包中。游戏API包...

    j2me 中文教程 开发环境 J2ME语言

    这一特别的小型数据库使得MIDP 的数据保存变得很特 别。 第六章“GAME API” 介绍了 MIDP 2.0 相对于1.0 来说,最大的变化——新添加的用于支 持游戏的API,它们被放在javax.microedition.lcdui.game 包中。游戏API ...

    J2ME中文教程

    这一特别的小型数据库使得MIDP 的数据保存变得很特别。 第六章“GAME API” 介绍了MIDP 2.0 相对于1.0 来说,最大的变化——新添加的用于支持游戏的API,它们被放在javax.microedition.lcdui.game 包中。游戏API 包...

    换器也兼容其他多版本的JAVA程序,比如S40手机的JAVA程序

    软件分【执行程序 Midp2Exe.exe】【数据库文件 MidpRuntimeDLL.dll】【批处理文件 ★自动打包★.bat】三部分。 【执行程序 Midp2Exe.exe】是一个DOS可执行文件,需要在DOS环境下执行,对没有DOS使用经验的人来说,...

    J2ME 中文教程1.01a

    这一特别的小型数据库使得MIDP的数据保存变得很特别。 第六章“GAME API” 介绍了MIDP 2.0相对于1.0来说,最大的变化——新添加的用于支持游戏的API,它们被放在javax.microedition.lcdui.game包中。游戏API包...

    MIDlet与Servlet通信的研究与设计

    信息设备特征)就是一种特定类型的特征,它包含一些附加的库,为与GUI 和数据库的交互提供了Java API。此外,这些Java API 提 出了诸如应用生命周期和特定设备联网之类的问题。使用MIDP 下的API 创建的各种应用即为...

    JAVA五子棋手机网络对战游戏的设计与实现-程序源代码-设计论文

    本文对以下几点内容做了重点研究和探讨: 1、 系统整体结构。 根据设计目标,结合普通网络游戏的运行流程,给出了系统总体设计方案,并探讨了系统设计时需要用到的关键技术。 2、 手机MIDP客户端的实现。 MIDP客户端...

    JAVA五子棋手机网络对战游戏的设计与实现(源代码+lw).zip

    本文对以下几点内容做了重点研究和探讨: 1、系统整体结构。 根据设计目标,结合普通网络游戏的运行流程,给出了系统总体设计方案,并探讨了系统设计时需要用到的关键技术。 2、手机MIDP客户端的实现。 MIDP客户端是...

    JAVA五子棋手机网络对战游戏的设计与实现(源代码+论文)

    本文对以下几点内容做了重点研究和探讨: 1、系统整体结构。 根据设计目标,结合普通网络游戏的运行流程,给出了系统总体设计方案,并探讨了系统设计时需要用到的关键技术。 2、手机MIDP客户端的实现。 MIDP客户端是...

    基于java的五子棋手机网络对战游戏系统设计与实现毕业设计(源代码+说明报告)

    2、 MIDP客户端的实现,MIDP客户端是游戏的唯一客户端,主要功能包括连接服务器进行身份验证、进行游戏并不断的与服务器交换数据。 3、 后台系统的设计与实现,后台用来处理与数据库的互联来验证用户身份、处理由...

    五子棋网络对战游戏的设计与实现.rar

    2、MIDP客户端的实现,MIDP客户端是游戏的唯一客户端,主要功能包括连接服务器进行身份验证、进行游戏并不断的与服务器交换数据。 3、后台系统的设计与实现,后台用来处理与数据库的互联来验证用户身份、处理由...

    [计算机毕设]基于java的五子棋手机网络对战游戏系统设计与实现(源代码+项目报告).zip

    2、 MIDP客户端的实现,MIDP客户端是游戏的唯一客户端,主要功能包括连接服务器进行身份验证、进行游戏并不断的与服务器交换数据。 3、 后台系统的设计与实现,后台用来处理与数据库的互联来验证用户身份、处理由...

    基于java的五子棋手机网络对战游戏系统设计与实现毕业设计(源代码+项目报告).zip

    2、 MIDP客户端的实现,MIDP客户端是游戏的唯一客户端,主要功能包括连接服务器进行身份验证、进行游戏并不断的与服务器交换数据。 3、 后台系统的设计与实现,后台用来处理与数据库的互联来验证用户身份、处理由...

    基于JAVA的五子棋手机网络对战游戏的设计与实现.doc

    2、 MIDP客户端的实现,MIDP客户端是游戏的唯一客户端,主要功能包括连接服务器进行身份验证、进行游戏并不断的与服务器交换数据。 3、 后台系统的设计与实现,后台用来处理与数据库的互联来验证用户身份、处理由...

    基于JAVA毕业设计-JAVA五子棋手机网络对战游戏的设计与实现(源代码+论文).rar

    后台用来处理与数据库的互联来验证用户身份、处理由客户端发送过来的数据。 由于受到客观条件的限制,本系统的测试是在三星手机模拟器上完成的,但它仍不失具一定的实用价值。 关键词:J2ME;手机游戏;servlet

Global site tag (gtag.js) - Google Analytics