【iOS-Android开发对照】之 数据存储

写在前面的话

相比Android和iOS,我认为Android的数据存储更开放一些。Android天生就能够使用多Java I/O;并且天生开放的特性,开发人员能够直接在SD卡中读写文件,自由度比較高。缺点吗,也是由于太开放,所以Android的相冊和目录都慘不忍睹。

Android本身自带Java的反射和注解,非常早就有了ORM数据库。这里解释一下,ORM就是 Object Relation Mapping, 对象关系映射。 通过建立对象来生成数据库字段,大大简化了代码。

Android的ORM我用过 GreenDaoActiveAndroid , GreenDao须要写Java项目来生成,并且lib包也比較多。

后来我用ActiveAndroid,相似于Ruby的ORM存储方式,用起来比較顺手。

IOS有Core Data, 可是用起来比較复杂。我一開始是直接使用 FMDB ,由于是SQLite的封装。还须要写SQLite代码。写起来还是比較麻烦。 当然,如今有了 MagicalRecord 。相似ORM数据库的Core Data封装, 能简化不少代码。


Android的4种数据存储方式

1 使用SharedPreferences存储数据;

SharedPreferences是用来存储一些Key/Value相似的成对的基本数据类型。

它仅仅能存储基本数据类型,也即int, long, boolean, String, float。

IOS相对的就是NSUserDefaults;

以下是演示样例代码:

void WriteSharedPreferences(String strName,String strPassword){
SharedPreferences user = getSharedPreferences(“user_info”,Context.MODE_PRIVATE);
user.edit();
user.putString(“NAME”, strName);
user.commit();
} void ReadSharedPreferences(){
String strName,strPassword;
SharedPreferences user = getSharedPreferences(“user_info”,Context.MODE_PRIVATE);
strName = user.getString(“NAME”,””);
}

SharedPreferences是採用了XML格式将数据存储到设备中,在DDMS中的File Explorer中的/data/data//shares_prefs下.

SharedPreferences相同是沙盒机制:仅仅能在同一个包内使用。不能在不同的包之间使用。

<?xml version=”1.0″ encoding=”UTF-8″?

>
<map>
<string name=”NAME”>XXXX</string>
</map>

2 文件存储数据;

Internal Storage内部存储空间

这里是指手机内置的存储空间,称为内部存储。

使用内部存储主要有二个方式。一个是文件操作,一个是目录操作.

Context提供了两个方法来打开数据文件中的文件IO流

FileInputStream openFileInput(String name);
FileOutputStream(String name , int mode).

Context还提供了例如以下几个重要的方法:

getDir(String name , int mode); //在应用程序的数据目录下获取或者创建name相应的子目录
File getFilesDir(); //获取该应用程序的数据目录得绝对路径
String[] fileList(); //返回该应用数据目录的所有文件

Context.openFileOutput(String fileName, int mode)生成的文件自己主动存储在/data/data/Package Name/files目录下。其全路径是/data/data/Package Name/files/fileName

注意下。这里的參数fileName不能够包括路径切割符(如”/”).

内部存储空间应该用来保存比較重要的数据。apk被卸载时,apk在内部存储空间的文件数据将被删除。

演示样例代码:

FileOutputStream  output = Context.openOutputFile(filename, Context.MODE_PRIVATE);
output.write(data);// use output to write whatever you like
output.close();
FileInputStream input = Context.openInputFile(filename);
input.read();
input.close();
public String read() {
try {
FileInputStream inStream = this.openFileInput("message.txt");
byte[] buffer = new byte[1024];
int hasRead = 0;
StringBuilder sb = new StringBuilder();
while ((hasRead = inStream.read(buffer)) != -1) {
sb.append(new String(buffer, 0, hasRead));
} inStream.close();
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
} public void write(String msg){
// 步骤1:获取输入值
if(msg == null) return;
try {
// 步骤2:创建一个FileOutputStream对象,MODE_APPEND追加模式
FileOutputStream fos = openFileOutput("message.txt",
MODE_APPEND);
// 步骤3:将获取过来的值放入文件
fos.write(msg.getBytes());
// 步骤4:关闭数据流
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}

External Storage外部存储空间

就是读写sdcard上的文件

当中读写步骤按例如以下进行:

1 调用Environment的getExternalStorageState()方法推断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,例如以下代码将返回true

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

2 调用Environment.getExternalStorageDirectory()方法来获取外部存储器。也就是SD卡的目录,或者使用”/mnt/sdcard/”目录

3 使用IO流操作SD卡上的文件

须要权限:

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

演示样例代码:

// 文件写操作函数
private void write(String content) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) { // 假设sdcard存在
File file = new File(Environment.getExternalStorageDirectory()
.toString()
+ File.separator
+ DIR
+ File.separator
+ FILENAME); // 定义File类对象
if (!file.getParentFile().exists()) { // 父目录不存在
file.getParentFile().mkdirs(); // 创建目录
}
PrintStream out = null; // 打印流对象用于输出
try {
out = new PrintStream(new FileOutputStream(file, true)); // 追加文件
out.println(content);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close(); // 关闭打印流
}
}
} else { // SDCard不存在。使用Toast提示用户
Toast.makeText(this, "保存失败,SD卡不存在! ", Toast.LENGTH_LONG).show();
}
} // 文件读操作函数
private String read() { if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) { // 假设sdcard存在
File file = new File(Environment.getExternalStorageDirectory()
.toString()
+ File.separator
+ DIR
+ File.separator
+ FILENAME); // 定义File类对象
if (!file.getParentFile().exists()) { // 父目录不存在
file.getParentFile().mkdirs(); // 创建目录
}
Scanner scan = null; // 扫描输入
StringBuilder sb = new StringBuilder();
try {
scan = new Scanner(new FileInputStream(file)); // 实例化Scanner
while (scan.hasNext()) { // 循环读取
sb.append(scan.next() + "\n"); // 设置文本
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (scan != null) {
scan.close(); // 关闭打印流
}
}
} else { // SDCard不存在。使用Toast提示用户
Toast.makeText(this, "读取失败,SD卡不存在! ", Toast.LENGTH_LONG).show();
}
return null;
}

3 SQLite数据库存储数据。

这里不具体说了,SQLite3都是通用的。能够參考学习:w3school, 我iOS写SQLite关系表把这个又学了一遍。

简单代码例如以下:

 db.executeSQL(String sql);
db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符。然后第二个參数是实际的參数集
db.insert(String table, String nullColumnHack, ContentValues values);
db.update(String table, Contentvalues values, String whereClause, String whereArgs);
db.delete(String table, String whereClause, String whereArgs);

4 使用ContentProvider存储数据;

Android内置的很多数据都是使用ContentProvider形式,供开发人员调用的(如视频。音频,图片,通讯录等),能够向其它应用共享其数据。

我曾经使用过ContentProvider和SQLiteDatabase CursorLoader相结合的方式,github地址

这里代码就不具体介绍了。


补充

Preference,File, DataBase这三种方式分别相应的目录是

/data/data/Package Name/Shared_Pref,

/data/data/Package Name/files,

/data/data/Package Name/database

iOS的5种数据存储方式

iOS都是沙盒存储。数据都在app的目录下。

1 NSUserDefaults

与Android的SharedPreferences原理相同。

NSUserDefaults能够存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary

保存数据:

NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];

NSString *name =@”default string“;
[defaults setObject:firstName forKey:@"name"]; UIImage *image=[[UIImage alloc]initWithContentsOfFile:@"photo.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 100);//UIImage对象转换成NSData
[defaults setObject:imageData forKey:@"image"]; [defaults synchronize];//用synchronize方法把数据持久化到standardUserDefaults数据库

读取数据:

NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];

NSString *name = [defaults objectForKey:@"name"];//依据键值取出name

NSData *imageData = [defaults dataForKey:@"image"];
UIImage *Image = [UIImage imageWithData:imageData];//NSData转换为UIImage

2 NSKeyedArchiver归档

採用归档的形式来保存数据,该数据对象须要遵守NSCoding协议。

对象相应的类必须提供encodeWithCoder:和initWithCoder:方法。对对象进行编码和解码。

以下的样例是从这篇博客中看到的:http://blog.csdn.net/dqjyong/article/details/7669252

比如对Possession对象归档保存。

定义Possession:
@interface Possession:NSObject<NSCoding>{//遵守NSCoding协议
NSString *name;//待归档类型
}
@implementation Possession
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:name forKey:@"name"];
}
-(void)initWithCoder:(NSCoder *)aDecoder{
name=[[aDeCoder decodeObjectforKey:@"name"] retain];
}

归档操作:

假设对Possession对象allPossession归档保存,仅仅须要NSCoder子类NSKeyedArchiver的方法archiveRootObject:toFile: 就可以。

NSString *path = [self possessionArchivePath];
[NSKeyedArchiver archiveRootObject:allPossessions toFile: path ];

解压操作:

相同调用NSCoder子类NSKeyedArchiver的方法unarchiveRootObject:toFile: 就可以
allPossessions = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] retain];

3 SQLite

这个不多说了,我具体就是直接看FMDB的文档。


4 CoreData

简述一下 Core Data数据持久化是对SQLite的一个升级,它是ios集成的.

我们在CoreData中使用的几个类。

1 NSManagedObjectModel(被管理的对象模型)

相当于实体,只是它包括 了实体间的关系

2 NSManagedObjectContext(被管理的对象上下文)

操作实际内容

作用:插入数据 查询 更新 删除

3 NSPersistentStoreCoordinator(持久化存储助理)

相当于数据库的连接器

4 NSFetchRequest(获取数据的请求)

相当于查询语句

5 NSPredicate(相当于查询条件)

6 NSEntityDescription(实体结构)

7 后缀名为.xcdatamodel的包

演示样例代码,封装好的CoreData管理类CoreDataManager.h:

#import <foundation foundation.h="">
#import "News.h"
#define TableName @"News" @interface CoreDateManager : NSObject @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; - (void)saveContext;
- (NSURL *)applicationDocumentsDirectory; //插入数据
- (void)insertCoreData:(NSMutableArray*)dataArray;
//查询
- (NSMutableArray*)selectData:(int)pageSize andOffset:(int)currentPage;
//删除
- (void)deleteData;
//更新
- (void)updateData:(NSString*)newsId withIsLook:(NSString*)islook; @end</foundation>
#import "CoreDateManager.h"

@implementation CoreDateManager

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator; - (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
} #pragma mark - Core Data stack // Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
} NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
} // Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"NewsModel" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
} // Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
} NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"NewsModel.sqlite"]; NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
} return _persistentStoreCoordinator;
} #pragma mark - Application's Documents directory // Returns the URL to the application's Documents directory.获取Documents路径
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
} //插入数据
- (void)insertCoreData:(NSMutableArray*)dataArray
{
NSManagedObjectContext *context = [self managedObjectContext];
for (News *info in dataArray) {
News *newsInfo = [NSEntityDescription insertNewObjectForEntityForName:TableName inManagedObjectContext:context];
newsInfo.newsid = info.newsid;
newsInfo.title = info.title;
newsInfo.imgurl = info.imgurl;
newsInfo.descr = info.descr;
newsInfo.islook = info.islook; NSError *error;
if(![context save:&error])
{
NSLog(@"不能保存:%@",[error localizedDescription]);
}
}
} //查询
- (NSMutableArray*)selectData:(int)pageSize andOffset:(int)currentPage
{
NSManagedObjectContext *context = [self managedObjectContext]; // 限定查询结果的数量
//setFetchLimit
// 查询的偏移量
//setFetchOffset NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; [fetchRequest setFetchLimit:pageSize];
[fetchRequest setFetchOffset:currentPage]; NSEntityDescription *entity = [NSEntityDescription entityForName:TableName inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
NSMutableArray *resultArray = [NSMutableArray array]; for (News *info in fetchedObjects) {
NSLog(@"id:%@", info.newsid);
NSLog(@"title:%@", info.title);
[resultArray addObject:info];
}
return resultArray;
} //删除
-(void)deleteData
{
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:TableName inManagedObjectContext:context]; NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setIncludesPropertyValues:NO];
[request setEntity:entity];
NSError *error = nil;
NSArray *datas = [context executeFetchRequest:request error:&error];
if (!error && datas && [datas count])
{
for (NSManagedObject *obj in datas)
{
[context deleteObject:obj];
}
if (![context save:&error])
{
NSLog(@"error:%@",error);
}
}
}
//更新
- (void)updateData:(NSString*)newsId withIsLook:(NSString*)islook
{
NSManagedObjectContext *context = [self managedObjectContext]; NSPredicate *predicate = [NSPredicate
predicateWithFormat:@"newsid like[cd] %@",newsId]; //首先你须要建立一个request
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:TableName inManagedObjectContext:context]];
[request setPredicate:predicate];//这里相当于sqlite中的查询条件。具体格式參考苹果文档 //https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pCreating.html
NSError *error = nil;
NSArray *result = [context executeFetchRequest:request error:&error];//这里获取到的是一个数组。你须要取出你要更新的那个obj
for (News *info in result) {
info.islook = islook;
} //保存
if ([context save:&error]) {
//更新成功
NSLog(@"更新成功");
}
}
@end

5 Plist

Plist (NSArray\NSDictionary) 也能够来存储数据。

全名 Property List。属性列表文件,它是一种用来存储串行化后的对象的文件。

属性列表文件的扩展名为.plist 。因此通常被称为 plist文件。文件是xml格式的。

具体可參考http://blog.csdn.net/mad1989/article/details/8560796

【iOS-Android开发对照】之 数据存储的更多相关文章

  1. Android开发笔记之: 数据存储方式详解

    无论是神马平台,神马开发环境,神马软件程序,数据都是核心.对于开发平台来讲,如果对数据的存储有良好的支持,那么对应用程序的开发将会有很大的促进作用.总体的来讲,数据存储方式有三种:一个是文件,一个是数 ...

  2. Android开发8:数据存储(二)——SQLite数据库和ContentProvider的使用

    前言 啦啦啦各位小伙伴们许久不见了~学期末和过年期间自己忙着做其他事没能及时更新Android开发系列课程的博客,实在是罪过罪过~ 好啦~废话不多说,进入我们今天的主题.今天我们将和大家学习其他的数据 ...

  3. Android开发-API指南-数据存储

    Storage Options 英文原文:http://developer.android.com/guide/topics/data/data-storage.html 采集日期:2015-02-0 ...

  4. Android开发手记(18) 数据存储三 SQLite存储数据

    Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 SQLite 是以嵌入式为目的 ...

  5. Android开发手记(17) 数据存储二 文件存储数据

    Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 本文主要介绍如何使用文件来存储 ...

  6. Android开发手记(20) 数据存储五 网络存储

    Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 安卓的网络存储比较简单,因为A ...

  7. Android开发手记(19) 数据存储四 ContentProvider

    转载自:http://www.cnblogs.com/devinzhang/archive/2012/01/20/2327863.html Android为数据存储提供了五种方式: 1.SharedP ...

  8. Android开发手记(16) 数据存储一 SharedPreferences

    Android为数据存储提供了五种方式: 1.SharedPreferences 2.文件存储 3.SQLite数据库 4.ContentProvider 5.网络存储 SharedPreferenc ...

  9. android开发系列之数据存储

    在我们的android实际开发过程,必不可少的一种行为操作对象就是数据.有些数据,对于用户而言是一次性的,这就要求我们每次进到App的时候,都需要去刷新数据.有些数据,对于用户而言又是具有一定时效性的 ...

  10. IOS开发数据存储篇—IOS中的几种数据存储方式

    IOS开发数据存储篇—IOS中的几种数据存储方式 发表于2016/4/5 21:02:09  421人阅读 分类: 数据存储 在项目开发当中,我们经常会对一些数据进行本地缓存处理.离线缓存的数据一般都 ...

随机推荐

  1. Open source and free log analysis and log management tools.

    Open source and free log analysis and log management tools. Maintained by Dr. Anton Chuvakin Version ...

  2. nodejs开发微信1——微信access-token和tickets的数据模型

    /* jshint -W079 */ /* jshint -W020 */ "use strict"; //var _ = require("lodash"); ...

  3. css学习笔记二

    下面来总结一下盒子模型,流式布局,浮动布局,层布局(定位布局). 1.盒子模型 有二种:IE盒子模型 和 标准w3c盒子模型 1)IE的盒子模型的content包含了padding和border 2) ...

  4. LCIS(线段树区间合并)

    LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  5. I Hate It(线段树)

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  6. Crisis of HDU(母函数)

    Crisis of HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  7. LeetCode总结 -- 高精度篇

    我们常见的一些主要的数据结构比方整型int或者浮点型float由于位数过多无法用内置类型存储,这时候我们就须要自己实现高精度的数据类型来进行存储和运算.这样的问题在实际产品中还是比較有用的,所以相对来 ...

  8. HDOJ2031进制转换

    项目做久了,我发现自己对代码的实现能力越来越差劲了!经过前一段时间找工作的经历就能够明显感觉的到自己的代码熟练度不够!因此,今后要多加练习.要想做好一个优秀的程序猿就要多写程序,多思考. ★结题思路 ...

  9. nyist 303序号互换(数学推理)

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=303 思路: 开始看错题了,以为最多只有两个字母. 字母转数字的表达式很容易看出来是:(2 ...

  10. 2014.9.23window对象

    一.window对象 Wondow.navigate(url); 跳转页面(与超链接的区别:可以加逻辑条件) Var a = Math.random(); 0-1之间随机数 Var a = parse ...