Chinaunix首页 | 论坛 | 博客
  • 博客访问: 281551
  • 博文数量: 179
  • 博客积分: 2995
  • 博客等级: 少校
  • 技术积分: 2100
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-13 10:21
文章分类

全部博文(179)

文章存档

2011年(1)

2010年(28)

2009年(150)

我的朋友

分类: LINUX

2010-01-18 10:05:00

笔者在前面的两篇文章《两个小时精通Android开发之界面篇》、《两个小时精通Android开发之按键映射篇》分别讲了无缝移植J2ME程序到Android平台上对界面和用户按键交互所做的适配接口,原则上利用这些接口原有的J2ME程序基本不用做任何的修改就可以运行在Android平台上,所以精通J2ME也就等于精通了Android

 

笔者这篇文章里要讲述的是J2ME平台和Android平台另外一个重要的不同点,那就是数据持久存储系统。

 

J2ME平台里采用RMS系统进行数据的持久存储,而Android平台则提供了丰富的接口进行数据的持久存储,但任何持久存储的本质无非就是数据串行化后被保存到磁盘空间上,仔细研究J2ME平台RMS系统的实现源码可以看到,J2ME是通过一个叫做RecordStoreFile的类进行数据持久化存储的,而这个RecordStoreFile类的实现如下:

 

public class RecordStoreFile {

   private static SecurityToken classSecurityToken;

    private static final String dbExtension = ".db";

    private RandomAccessStream recordStream;

    private String myStoragePath;

 

    public static void initSecurityToken(SecurityToken token) {

    if (classSecurityToken != null) {

        return;

    }

    classSecurityToken = token;

    }

 

    public RecordStoreFile(String uidPath)

    throws IOException

    {

    RandomAccessStream newStream;

    myStoragePath = uidPath;

 

    newStream = new RandomAccessStream(classSecurityToken);

    newStream.connect(myStoragePath, Connector.READ_WRITE);

    recordStream = newStream;

    }

 

    public static String getUniqueIdPath(String fileName) {

    return getStoragePath(fileName);

    }

   

    public static String getUniqueIdPath(String vendorName, String suiteName,

                     String fileName) {

    return getStoragePath(vendorName, suiteName, fileName);

    }

 

    public static boolean exists(String uidPath) {

    File file;

    file = new File(classSecurityToken);

    return file.exists(uidPath);

    }

 

   

    public static boolean deleteFile(String uidPath)

    {

    File file;

    file = new File(classSecurityToken);

    try {

        file.delete(uidPath);

        return true;

    } catch (IOException ioe) {

        return false;

    }

    }

   

    public void seek(int pos) throws IOException

    {

    recordStream.setPosition(pos);

    }

 

    public void write(byte[] buf) throws IOException

    {

    write(buf, 0, buf.length);

    }

 

    public void write(byte[] buf, int offset, int numBytes) throws IOException

    {

    recordStream.writeBytes(buf, offset, numBytes);

    }

   

    public int read(byte[] buf) throws IOException

    {

    return read(buf, 0, buf.length);

    }

 

    public int read(byte[] buf, int offset, int numBytes) throws IOException

    {

    return recordStream.readBytes(buf, offset, numBytes);

    }

 

    public void close() throws IOException

    {

    // close recordStream if it exists

    if (recordStream != null) {

        recordStream.disconnect();

        recordStream = null;

    }

    }

 

    public void truncate(int size) throws IOException

    {

    if (recordStream != null) {   

        recordStream.truncate(size);

    }   

    }

 

    public static String[] listRecordStores() {

        return listRecordStoresForSuite(new File(classSecurityToken),

            getStoragePath(null), false);

    }

 

    private static String[] listRecordStoresForSuite(File storage,

                                                     String suiteStorageRoot,

                                                     boolean rawNames) {

    Vector files;

    Vector names;

    String file;

    String asciiName;

   

    files = storage.filenamesThatStartWith(suiteStorageRoot);

    names = new Vector();

   

    // work through list of strings from the directory

    for (int i = 0; i < files.size(); i++) {

        file = (String)files.elementAt(i);

        if (file.endsWith(dbExtension)) {

                if (rawNames) {

                    names.addElement(file);

                } else {

                    asciiName = file.substring(suiteStorageRoot.length(),

                       file.length() - 3);

                    names.addElement(File.asciiFilenameToUnicode(asciiName));

                }

        }

    }

 

    if (names.size() == 0) {

        return null;

    }

   

    String[] rv = new String[names.size()];

    names.copyInto(rv);

    return rv;

    }

   

    public static void removeRecordStoresForSuite(SecurityToken token,

            String suiteStorageRoot) {

 

        File storage;

    String[] filenames;

   

    storage = new File(token);

        filenames = listRecordStoresForSuite(storage, suiteStorageRoot, true);

        if (filenames == null) {

            return;

        }

 

        for (int i = 0; i < filenames.length; i++) {

            try {

                storage.delete(filenames[i]);

            } catch (IOException ioe) {

                // move on to the next suite

            }

        }

    }

   

    public static boolean suiteHasRmsData(String suiteStorageRoot) {

    File storage = new File(classSecurityToken);

    Vector files = storage.filenamesThatStartWith(suiteStorageRoot);

 

    for (int i = 0; i < files.size(); i++) {

        String file = (String)files.elementAt(i);

        if (file.endsWith(dbExtension)) {

                return true;

            }

        }

 

        return false;

    }

 

    public static int spaceAvailable()

    {

    return new File(classSecurityToken).getBytesAvailableForFiles();

    }

 

    private static String getStoragePath(String name)

    {

    String str;

    MIDletSuite mSuite;

    StringBuffer path;

   

    mSuite = Scheduler.getScheduler().getMIDletSuite();

   

    str = mSuite.getStorageRoot();

    if (name != null) {

        path = new StringBuffer(str);

        // convert the unicode filename into a system acceptable string

        path.append(File.unicodeToAsciiFilename(name));

        path.append(dbExtension);

        str = path.toString();

    }

    return str;

    }

    private static String getStoragePath(String vendor, String suite,

                     String name) {

    String str = File.getStorageRoot();

    StringBuffer path = new StringBuffer(str);

    if (vendor != null && suite != null) {

        path.append(File.unicodeToAsciiFilename(vendor));

        path.append('_');

        path.append(File.unicodeToAsciiFilename(suite));

        path.append('_');

    }

    if (name != null) {

        path.append(File.unicodeToAsciiFilename(name));

        path.append(dbExtension);

        str = path.toString();

    }

    return str;

    }

}

 

可见,RMS系统也是通过IO把数据串行化后存储应用程序的空间内的,绝大多数的J2ME程序都需要利用RMS来进行数据的持久存储的,比如游戏积分、系统设置等。那么为了无缝移植J2MEAndroid平台,笔者自己写了一个简易的RMS系统,能满足绝大多数应用程序的需要。

 

Android下对文件的操作和J2ME基本一样,但是需要绑定一个Context上下文,以把文件保存到当前应用程序的目录下,这个目录在打开DDMS窗口后可以看到,具体位置是data/data/PACKAGE_NAME/files下面。

 

利用文件操作可以进行数据的读写,笔者封装的接口如下:

 

    public static boolean deleteFile(String fileName){     

        File file = new File(fileName);      

        if(file.isFile() && file.exists()){     

            file.delete();     

            System.out.println("删除单个文件"+fileName+"成功!");     

            return true;     

        }else{     

            System.out.println("删除单个文件"+fileName+"失败!");     

            return false;     

        }     

    }     

 

     public String read(String file) {

         String data = "";

         try {

              FileInputStream stream = System.getSystemHandler().getContext().openFileInput(file);

              StringBuffer sb = new StringBuffer();

              int c;

              while ((c = stream.read()) != -1) {

                   sb.append((char) c);

              }

              stream.close();

              data = sb.toString();

 

         } catch (FileNotFoundException e) {

              e.printStackTrace();

         } catch (IOException e) {

              e.printStackTrace();

         }

         return data;

     }

 

     public void write(String file, byte[] msg) {

         try {

              FileOutputStream stream = System.getSystemHandler().getContext().openFileOutput(file,Context.MODE_WORLD_WRITEABLE);

              stream.write(msg);

              stream.flush();

              stream.close();

         } catch (FileNotFoundException e) {

              e.printStackTrace();

         } catch (IOException e) {

              e.printStackTrace();

         }

     }

 

有了基本的读写数据操作,就可以封装RMS中常见的key-value的保存和读取了,代码实现如下:

 

public boolean put(String key, byte[] value) {

         boolean bSaveOk = false;

         byte[] data = null;

         if (value == null) {

              throw new NullPointerException();

         }

         ByteArrayOutputStream bout = null;

         DataOutputStream dout = null;

         try {

              bout = new ByteArrayOutputStream();

              dout = new DataOutputStream(bout);

              dout.writeUTF(key);

              dout.writeInt(value.length);

              dout.write(value, 0, value.length);

              data = bout.toByteArray();

 

              write(dbName,data);        

              bSaveOk = true;

         } catch (Exception e) {

              bSaveOk = false;

              e.printStackTrace();

         }

        

         return bSaveOk;

     }

 

     public byte[] getByteArray(String key) {

         ByteArrayInputStream bin = null;

         DataInputStream din = null;

         byte[] data = null;       

         try {

                   String valueKey = read(dbName);

                   din = new DataInputStream(new ByteArrayInputStream(valueKey.getBytes()));

 

                   while(din.available() > 0)

                   {

                       String getKey = din.readUTF();

                       int getLength = din.readInt();

    

                       data = new byte[getLength];

                       int bytesRead = 0;

                       while (bytesRead < data.length) {

                            int count = din.read(data, bytesRead, data.length

                                     - bytesRead);

                            if (count == -1)

                                 break;

                            bytesRead += count;

                       }

                      

                       if(getKey.equals(key))

                            break;

                   }

                                

                   din.close();

                   din = null;

         } catch (Exception e) {

              e.printStackTrace();

              data = null;

         }

         return data;

     }

}

阅读(1009) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~