利用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数据持久化的另外一种方式,不过大同小异,有兴趣的看官可以继续到我这里来看看.
最后:由于我也是刚刚了解这个东西,难免会有错误的敌方,欢迎各位大神不吝赐教,指出错误,小弟在此拜谢!