利用GCD进行数据持久化的方式(一)

最近在研究GCD,网上看了好多博客大部分都是关于异步,同步线程这些最基本的问题,在无意中翻阅文档的时候看到dispatch_io_t这个东西.发现GCD也可以用来对数据进行读取(Read/Write)操作,于是我决定仔细看看API,研究研究用法。

首先dispatch读取数据是属于 数据持久化的一种方式,相对于我们平常用的wirteToFile和其他的方式,dispatc可以分次读取,可以设定low_Water或者high_Water,也就是每次读取的下限和上限,我们利用这一点可以监控整个读取过程的progress,在读取之前我们首先要准备一条路径,这个没有什么特别的就是咱们平常用的path

1 NSString *path = [NSString stringWithFormat:@"%@/Documents/myData.text",NSHomeDirectory()];
2     
3     NSLog(@"   %@",path);

打印出来有助于检查文件是不是被写进去了,但是这里我发现了一个问题,不过不影响读取,稍后我在抛出这个问题

GCD的读写需要我们事先获取文件打开的权限和一个文件的描述符,也就是下面这个东西

dispatch_fd_t fd = open(strcpy(myChar, (char *)[path UTF8String]), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);

我来解释一下这个鬼的几个参数,第一个使我们路径转成的char类型,没办法,纯C的东西.后面的是可变长度参数类型,这里填写的是我们获取的权限,下面是参数的解释

/*
 O_RDONLY 以只读方式打开文件
 O_WRONLY 以只写方式打开文件
 O_RDWR 以可读写方式打开文件. 上述三种旗标是互斥的, 也就是不可同时使用, 但可与下列的旗标利用OR(|)运算符组合.
 O_CREAT 若欲打开的文件不存在则自动建立该文件.
 O_EXCL 如果O_CREAT 也被设置, 此指令会去检查文件是否存在. 文件若不存在则建立该文件, 否则将导致打开文件错误. 此外, 若O_CREAT 与O_EXCL 同时设置, 并且欲打开的文件为符号连接, 则会打开文件失败.
 O_NOCTTY 如果欲打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机.
 O_TRUNC 若文件存在并且以可写的方式打开时, 此旗标会令文件长度清为0, 而原来存于该文件的资料也会消失.
 O_APPEND 当读写文件时会从文件尾开始移动, 也就是所写入的数据会以附加的方式加入到文件后面.
 O_NONBLOCK 以不可阻断的方式打开文件, 也就是无论有无数据读取或等待, 都会立即返回进程之中.
 O_NDELAY 同O_NONBLOCK.
 O_SYNC 以同步的方式打开文件.
 O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接, 则会令打开文件失败.
 O_DIRECTORY 如果参数pathname 所指的文件并非为一目录, 则会令打开文件失败。注:此为Linux2. 2 以后特有的旗标, 以避免一些系统安全问题.
 */
/*
 S_IRWXU00700 权限, 代表该文件所有者具有可读、可写及可执行的权限.
 S_IRUSR 或S_IREAD, 00400 权限, 代表该文件所有者具有可读取的权限.
 S_IWUSR 或S_IWRITE, 00200 权限, 代表该文件所有者具有可写入的权限.
 S_IXUSR 或S_IEXEC, 00100 权限, 代表该文件所有者具有可执行的权限.
 S_IRWXG 00070 权限, 代表该文件用户组具有可读、可写及可执行的权限.
 S_IRGRP 00040 权限, 代表该文件用户组具有可读的权限.
 S_IWGRP 00020 权限, 代表该文件用户组具有可写入的权限.
 S_IXGRP 00010 权限, 代表该文件用户组具有可执行的权限.
 S_IRWXO 00007 权限, 代表其他用户具有可读、可写及可执行的权限.
 S_IROTH 00004 权限, 代表其他用户具有可读的权限
 S_IWOTH 00002 权限, 代表其他用户具有可写入的权限.
 S_IXOTH 00001 权限, 代表其他用户具有可执行的权限.
 */

接下来,我们要给gcd准备一条线程,创建线程有好多种方式,这里我们使用带有标志的,便于以后线程出问题调试,嘿嘿

dispatch_queue_t myQueue = dispatch_queue_create("myOnlyQueue", DISPATCH_QUEUE_CONCURRENT);

搞定这些之后我们需要给gcd搞一个通道channle,创建通道的方式也是有好几种,我先给大家介绍一下创建通道的几个参数吧

dispatch_io_create_with_path(dispatch_io_type_t type,
    const char *path, int oflag, mode_t mode,
    dispatch_queue_t queue,
    void (^cleanup_handler)(int error));

第一个是通道本身的type,只有两种,一个是  0  这种方式会忽略我们下面要创建的offset参数

DISPATCH_IO_STREAM

另外一个是    1  需要我们创建一个offset参数用来找到file的descriptor

DISPATCH_IO_RANDOM

第二个参数是路径,第三个是旗标,搞过Linux的应该是知道的,这里我们用O_RDWR,第四个是如果放弃操作或者打开指定文件失败的错误码,一般写0,第四个就是我们上面创建的queue,最后的是我们创建通道时的错误码

dispatch_io_t dispatchio = dispatch_io_create_with_path(DISPATCH_IO_STREAM, path.UTF8String, O_RDWR, 0, myQueue, ^(int error) {
        close(fd);
    });

上面只是创建通道的一种方式,如果我记得不错的话应该是一共有4种,其他的各位看官们可以自己试试

首先我们来搞一个简单的东西写入文件

const char daxiao[] = "Hello  World !";
off_t offt = sizeof(daxiao);
size_t size = sizeof(daxiao);

然后我们开始把上面这句话搞到gcd的data里面去

dispatch_data_t datas = dispatch_data_create(daxiao, size, myQueue, NULL);

最后开始我们的写入操作

dispatch_io_write(dispatchio, 0, datas, myQueue, ^(bool done, dispatch_data_t data, int error) {
       
        
    });

这样我们就可以把Hello  World !写入文件了,从路径打开文件查看,的确写入了,但是不知道为何后面会多出许多没用的东西来,这个也是我最一开始提到的问题,目前我还没有闹明白,如果哪位大神知道是咋回事,还请告知小弟,不胜感激!!!

不过多出来的东西不影响我们读取数据

下面我们开始读取已经写好的文件

很简单

dispatch_io_set_high_water(dispatchio, 1);
dispatch_io_read(dispatchio, 0, 10, myQueue, ^(bool done, dispatch_data_t data, int error) {
       
   NSString *string = [[NSString alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding];
   if (done) {
            
     NSLog(@" %@ ",string);
            
    } else {
            
     NSLog(@"我的大刀早已饥渴难耐了!");
            
    }

第一行就是我说的设定最高读取上限,后面那个1 是最高读取1字节,所以如果你运行成功后会发现 dispatch_io_read后面的回调block会走好几遍,也就是说

 NSLog(@"我的大刀早已饥渴难耐了!");

这个会打印好多次,利用这一点我们可以监控读取文件的进度,这种方式就是利用线程多次读取文件,相比普通的方式可以提高速度.

好吧,我文笔有限,后面我会继续讲解GCD数据持久化的另外一种方式,不过大同小异,有兴趣的看官可以继续到我这里来看看.

最后:由于我也是刚刚了解这个东西,难免会有错误的敌方,欢迎各位大神不吝赐教,指出错误,小弟在此拜谢!

 

posted @ 2016-01-15 10:38  有码才合法  阅读(1189)  评论(2编辑  收藏  举报