两个小时精通Android开发之数据持久存储篇

作者:孙东风 2010-01-15(转载务必注明出处)

笔者在前面的两篇文章《两个小时精通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;

}

}

更多相关文章

  1. 一句话锁定MySQL数据占用元凶
  2. android ContentProvider ApplyBatch
  3. SnappyDB—Android上的NoSQL数据库
  4. Android(安卓)对用户名密码进行加密操作存储在本地
  5. Android新手入门2016(3)--Android真机调试
  6. Android解决读取txt文件中文乱码问题,reload和cnvert区别,按行读取
  7. Android(安卓)OpenGLES2.0(十一)——利用OpenGLES做Camera预览
  8. Smobiler如何实现.net一键开发,ios和android跨平台运行
  9. Android(安卓)分享 - 向其它 App 发送数据

随机推荐

  1. Android(安卓)浏览器插件开发-插件库
  2. Android(安卓)xUtils3源码解析之注解模块
  3. android ANR 问题
  4. ubuntu下反翻译android apk
  5. 关于Android(安卓)properties 中ro开头无
  6. Android开发 之 图片浏览
  7. 一键多渠道打包 只需1秒
  8. Android自定义饼图TTJPieChart
  9. Android(安卓)- AppCompatEditText 重写,
  10. Android(安卓)RatingBar 评分条