【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. Html 笔记1

    标题(Heading)是通过 <h1> - <h6> 等标签进行定义的. <h1>这是标题</h1> 段落是通过 <p> 标签进行定义的. ...

  2. MYSQL 巧用count,sum进行统计数据

    SELECT a.user,count(b.order_id) as subcount,sum(if(b.verifysta='Y',1,0)) as passcount FROM vicidial_ ...

  3. 杭电 1272 POJ 1308 小希的迷宫

    这道题是我学了并查集过后做的第三个题,教我们的学姐说这是并查集的基础题,所以有必要牢牢掌握. 下面就我做这道题的经验,给大家一些建议吧!当然,我的建议不是最好的,还请各位大神指出我的错误来,我也好改正 ...

  4. yum subversion puppet puppet-server

    yum -y install ruby ruby-libs ruby-shadow yum -y install puppet puppet-server facter yum -y install ...

  5. 网易云课堂_C语言程序设计进阶_第5周:链表_1逆序输出的数列

    1 逆序输出的数列(10分) 题目内容: 你的程序会读入一系列的正整数,预先不知道正整数的数量,一旦读到-1,就表示输入结束.然后,按照和输入相反的顺序输出所读到的数字,不包括最后标识结束的-1. 输 ...

  6. Mac 上开启一个简单的服务器

    终端输入命令: python -m SimpleHTTPServer 会开启一个端口为8000的本地服务器.

  7. 一个神奇的bug

    在使用touch命令创建了一个swift文件后,如果用xcode打开该文件,然后输入 #!/usr/bin/env xcrun swift 接着你就会发现,xcode崩溃了.

  8. B. Wet Shark and Bishops(思维)

    B. Wet Shark and Bishops time limit per test 2 seconds memory limit per test 256 megabytes input sta ...

  9. 杂记之activity之间的跳转

    代码结构图 manifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xml ...

  10. 【每日一摩斯】-Troubleshooting: High CPU Utilization (164768.1) - 系列6

    如果问题是一个正运行的缓慢的查询SQL,那么就应该对该查询进行调优,避免它耗费过高的CPU资源.如果它做了许多的hash连接和全表扫描,那么就应该添加索引以提高效率. 下面的文章可以帮助判断查询的问题 ...