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


    【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() + " "); // 设置文本 } 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 PossessionNSObject<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 (NSArrayNSDictionary) 也能够来存储数据。

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

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

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

  • 相关阅读:
    R语言学习——欧拉计划(11)Largest product in a grid
    R语言学习——欧拉计划(3)Largest prime factor 求最大质因数
    R语言学习——欧拉计划(3)Largest prime factor 求最大质因数
    python中matplotlib的颜色及线条控制
    python中matplotlib的颜色及线条控制
    R语言学习——欧拉计划(1)Multiples of 3 and 5
    R语言学习——欧拉计划(1)Multiples of 3 and 5
    R语言学习——循环判断语句
    R语言学习——循环判断语句
    R语言学习——数据框
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5195748.html
Copyright © 2020-2023  润新知