版本:iOS13.5
io.h
dispatch其他文件通道
索引
-
dispatch_read
通过文件描述符异步读取数据 -
dispatch_write
通过文件描述符异步写入数据 -
dispatch_io_create
根据文件描述符创建调度I / O通道 -
dispatch_io_create_with_path
根据路径名创建调度I / O通道 -
dispatch_io_create_with_io
从现有的调度I / O通道创建一个新的调度I / O通道 -
dispatch_io_read
在指定的I / O通道上异步执行读取操作 -
dispatch_io_write
在指定的I / O通道上异步执行写入操作 -
dispatch_io_close
关闭指定的I / O通道以进行新的读取或写入操作 -
dispatch_io_barrier
在指定的I / O通道上安排屏障操作 -
dispatch_io_get_descriptor
获取I / O通道的文件描述符 -
dispatch_io_set_high_water
设置I / O通道上所有操作的高水位线 -
dispatch_io_set_low_water
设置I / O通道上所有操作的低水位线 -
dispatch_io_set_interval
设置一个纳秒间隔,所有操作的回调将按间隔时间排队。
详解
- 通过文件描述符异步读取数据
void dispatch_read(dispatch_fd_t fd, size_t length,
dispatch_queue_t queue, void (^handler)(dispatch_data_t data, int error));
当异步读取操作完成或发生错误时,将handler加入队列queue再执行。
fd 要读取数据的文件描述符 可通过下面代码创建
//文件位置
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
#define O_RDONLY 0x0000 //只读
#define O_WRONLY 0x0001 //只写
#define O_RDWR 0x0002 //读写
#define O_ACCMODE 0x0003 //
length 从文件描述符读取的数据长度 若为SIZE_MAX,表示读取文件描述符当前可用的所有数据。
queue 队列 通过dispatch_queue_create
创建
handler 读取完成时回调
data 从文件描述符读取的数据
error 读取操作的错误;如果读取成功,则为0。
例:
//文件位置
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
//创建fd
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
//创建队列
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_read(fd, SIZE_MAX, queue, ^(dispatch_data_t _Nonnull data, int error) {
UIImage *image = [UIImage imageWithData:(NSData *)data];
NSLog(@"%f %f", image.size.width, image.size.height);
close(fd);
});
- 通过文件描述符异步写入数据
void dispatch_write(dispatch_fd_t fd, dispatch_data_t data,
dispatch_queue_t queue, void (^handler)(dispatch_data_t _Nullable data, int error));
当异步写入操作完成或发生错误时,将handler加入队列queue再执行。
data 要写入文件描述符的数据对象
handler 写入操作完成时回调
data 无法写入I / O通道的数据,写入成功时为NULL。
error 写入操作的错误;如果写入成功,则为0。
例:
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
NSString *path1 = [[NSBundle mainBundle] pathForResource:@"333" ofType:@"jpeg"];
dispatch_fd_t fd1 = open(path1.UTF8String, O_RDWR);
char charbuffer[] = {"1234567890"};
dispatch_data_t data = dispatch_data_create(charbuffer, 10 * sizeof(char), queue, NULL);
dispatch_write(fd1, data, queue, ^(dispatch_data_t _Nullable data, int error) {
NSLog(@"%d", error);
close(fd1);
});
- 根据文件描述符创建调度I / O通道
dispatch_io_t dispatch_io_create(dispatch_io_type_t type, dispatch_fd_t fd,
dispatch_queue_t queue, void (^cleanup_handler)(int error));
type io通道类型
//此类型通道的读取和写入操作是按顺序执行的(按创建顺序)
//并且在操作开始执行时在文件指针位置处读取/写入数据。
//可以同时执行不同类型的操作(读与写)。
//传递给此类型通道上的操作的偏移量off_t offset将无效
#define DISPATCH_IO_STREAM 0
//可以同时执行这种类型的通道上的读取和写入操作,并以指定的偏移量off_t offset读取/写入数据。
//为无法查找的文件描述符创建此类型的通道将导致错误。
#define DISPATCH_IO_RANDOM 1
cleanup_handler 当系统放弃对文件描述符的控制权时要放入队列queue中的回调
error 如果由于创建通道失败使系统放弃控制,则为错误,否则为0
例:
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {
close(fd);
});
- 根据路径名创建调度I / O通道
dispatch_io_t 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));
当通道上的第一个I / O操作准备好执行时,指定的路径,oflag和mode参数将传递给open(2)
path 绝对路径
oflag 在路径中打开文件时传递给open(2)的标志
mode 在路径创建文件时传递给open(2)的模式,否则为0。
cleanup_handler 系统关闭路径下的文件时放入队列queue的回调
error 如果创建或打开指定文件的通道失败使系统放弃控制时,则为错误,否则为0
例:
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_io_t io1 = dispatch_io_create_with_path(DISPATCH_IO_RANDOM, path.UTF8String, 0, 0, queue, ^(int error) {
close(fd);
});
- 从现有的调度I / O通道创建一个新的调度I / O通道
dispatch_io_t dispatch_io_create_with_io(dispatch_io_type_t type, dispatch_io_t io,
dispatch_queue_t queue, void (^cleanup_handler)(int error));
新通道继承与现有通道关联的文件描述符或路径名,但不继承其通道类型type或策略
策略为(dispatch_io_set_high_water
、dispatch_io_set_low_water
、dispatch_io_set_interval
)等
io 原io通道
cleanup_handler 当系统放弃对文件描述符的控制(或重新关闭路径中的文件)时放入队列queue的回调
error 如果由于创建通道失败使系统放弃控制,则为错误,否则为0
例:
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {
close(fd);
});
dispatch_io_t io2 = dispatch_io_create_with_io(DISPATCH_IO_RANDOM, io, queue, ^(int error) {
});
- 在指定的I / O通道上异步执行读取操作
void dispatch_io_read(dispatch_io_t channel, off_t offset,size_t length,
dispatch_queue_t queue,dispatch_io_handler_t io_handler);
根据系统的一般负载和在I / O通道上指定的策略,将io_handler回调在queue上排队一次或多次。
channel I / O通道
offset 相对于从其开始读取的通道位置的偏移量(仅适用于DISPATCH_IO_RANDOM
)。
length 从I / O通道读取的数据长度,若为SIZE_MAX,表示全部读取
io_handler 准备好传递数据时的回调
typedef void (^dispatch_io_handler_t)(bool done, dispatch_data_t _Nullable data,
int error);
done 指示操作是否完成
data 从I / O通道读取的数据的对象,或者为NULL
error 读取操作的错误;如果读取成功,则为0
例:
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {
close(fd);
});
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (error == 0) {
size_t len = dispatch_data_get_size(data);
if (len > 0) {
UIImage *image = [UIImage imageWithData:(NSData *)data];
NSLog(@"%f %f", image.size.width, image.size.height);
}
}
if (done) {
NSLog(@"已全部读取完成");
}
});
输出:
658.000000 298.000000
已全部读取完成
- 在指定的I / O通道上异步执行写入操作
void dispatch_io_write(dispatch_io_t channel, off_t offset, dispatch_data_t data,
dispatch_queue_t queue, dispatch_io_handler_t io_handler);
根据系统的一般负载和在I / O通道上指定的策略,将io_handler回调在queue上排队一次或多次。
offset 相对于开始写入的通道位置偏移(仅适用于DISPATCH_IO_RANDOM
)
data 要写入I / O通道的数据。数据对象将由系统保留,直到写入操作完成
io_handler 传递数据时的回调
typedef void (^dispatch_io_handler_t)(bool done, dispatch_data_t _Nullable data,
int error);
done 指示操作是否完成
data 被写入I / O通道的剩余的数据对象,若全部写入则为NULL
error 写入操作的错误;如果写入成功,则为0
例:
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {
close(fd);
});
char charbuffer[] = {"1234567890"};
dispatch_data_t data = dispatch_data_create(charbuffer, 10 * sizeof(char), queue, NULL);
dispatch_io_write(io, 0, data, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (done) {
NSLog(@"已全部写入完成");
}
});
输出:
已全部写入完成
- 关闭指定的I / O通道以进行新的读取或写入操作
void dispatch_io_close(dispatch_io_t channel, dispatch_io_close_flags_t flags);
flags 关闭操作的标志
#define DISPATCH_IO_STOP 0x1
当通道关闭时,停止对通道的未完成操作
- 在指定的I / O通道上安排屏障操作
void dispatch_io_barrier(dispatch_io_t channel, dispatch_block_t barrier);
barrier回调会放入通道channel的队列queue中,通道上的所有先前的调度操作都会完成。但直到barrier回调执行之前,之后添加的调度操作都不会开始。
barrier 屏障操作回调typedef void (^dispatch_block_t)(void);
例:
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {
close(fd);
});
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (done) {
NSLog(@"读取操作1完成");
}
});
dispatch_io_barrier(io, ^{
sleep(10);
});
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (done) {
NSLog(@"读取操作2完成");
}
});
输出:操作1完成10秒后操作2才完成
16:20:19.506332+0800 DEMO[67133:7469651] 读取操作1完成
16:20:29.510332+0800 DEMO[67133:7469652] 读取操作2完成
- 获取I / O通道的文件描述符
dispatch_fd_t dispatch_io_get_descriptor(dispatch_io_t channel);
- 设置I / O通道上所有操作的高水位线
void dispatch_io_set_high_water(dispatch_io_t channel, size_t high_water);
high_water 高水位线的字节数,默认为SIZE_MAX
- 设置I / O通道上所有操作的低水位线
void dispatch_io_set_low_water(dispatch_io_t channel, size_t low_water);
I / O管道通常接收大于低水位线的数据量。如果需要固定大小的数据量,则将低水位标记和高水位标记都设置为该大小。
low_water 低水位线的字节数,默认未指定,若要让操作不执行回调,请将此值设为SIZE_MAX
例:
dispatch_io_set_high_water(io, 10000);
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
NSLog(@"error=%d data_size =%ld", error, dispatch_data_get_size(data));
});
输出:总共读取了5次 每次读取最大为10000
error=0 data_size =10000
error=0 data_size =10000
error=0 data_size =10000
error=0 data_size =2909
error=0 data_size =0
例:
dispatch_io_set_high_water(io, 9000);
dispatch_io_set_low_water(io, 8000);
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
NSLog(@"error=%d data_size =%ld", error, dispatch_data_get_size(data));
});
输出:ps:```dispatch_io_set_low_water```用法不明,有待开发
error=0 data_size =9000
error=0 data_size =9000
error=0 data_size =9000
error=0 data_size =5909
error=0 data_size =0
- 设置一个纳秒间隔,所有操作的回调将按间隔时间排队。
void dispatch_io_set_interval(dispatch_io_t channel,
uint64_t interval, dispatch_io_interval_flags_t flags);
这允许应用程序接收有关读取和写入操作进度的定期反馈,例如为了显示进度条。
interval 各回调之间的间隔时间(纳秒)
flags 数据传递行为的标志
#define DISPATCH_IO_STRICT_INTERVAL 0x1
即使准备好传递的数据量低于低水位线(或零),也可以按通道的间隔设置让回调排队。
例:
dispatch_io_set_interval(io, 1 * NSEC_PER_SEC, DISPATCH_IO_STRICT_INTERVAL);
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (done) {
NSLog(@"读取操作1完成");
}
});
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (done) {
NSLog(@"读取操作2完成");
}
});
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (done) {
NSLog(@"读取操作3完成");
}
});
输出:并没有间隔一秒 不知为何
16:58:43.854467+0800 DEMO[67854:7526310] 读取操作1完成
16:58:43.854501+0800 DEMO[67854:7526297] 读取操作2完成
16:58:43.854521+0800 DEMO[67854:7526328] 读取操作3完成
用法
用法1:并行
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {
close(fd);
});
long long fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil].fileSize;
NSMutableData *totalData = [[NSMutableData alloc] initWithLength:fileSize];
dispatch_group_t group = dispatch_group_create();
size_t offset = 1024;
for (off_t currentSize = 0; currentSize <= fileSize; currentSize += offset) {
dispatch_group_enter(group);
dispatch_io_read(io, currentSize, offset, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (error == 0) {
size_t len = dispatch_data_get_size(data);
if (len > 0) {
const void *bytes = NULL;
(void)dispatch_data_create_map(data, &bytes, &len);
//当queue为DISPATCH_QUEUE_CONCURRENT并行时 通过replaceBytesInRange来替换数据
[totalData replaceBytesInRange:NSMakeRange(currentSize, len) withBytes:bytes];
}
}
if (done) {
dispatch_group_leave(group);
}
});
}
dispatch_group_notify(group, queue, ^{
UIImage *image = [UIImage imageWithData:totalData];
NSLog(@"%f %f", image.size.width, image.size.height);
});
用法2:串行
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_SERIAL);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {
close(fd);
});
long long fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil].fileSize;
NSMutableData *totalData = [[NSMutableData alloc] init];
dispatch_group_t group = dispatch_group_create();
size_t offset = 1024;
for (off_t currentSize = 0; currentSize <= fileSize; currentSize += offset) {
dispatch_group_enter(group);
dispatch_io_read(io, currentSize, offset, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (error == 0) {
size_t len = dispatch_data_get_size(data);
if (len > 0) {
//当queue为DISPATCH_QUEUE_SERIAL串行时 通过appendData直接合并数据
[totalData appendData:(NSData *)data];
}
}
if (done) {
dispatch_group_leave(group);
}
});
}
dispatch_group_notify(group, queue, ^{
UIImage *image = [UIImage imageWithData:totalData];
NSLog(@"%f %f", image.size.width, image.size.height);
});
用法3:io类型为DISPATCH_IO_STREAM
NSString *path = [[NSBundle mainBundle] pathForResource:@"222" ofType:@"jpeg"];
dispatch_fd_t fd = open(path.UTF8String, O_RDWR);
dispatch_queue_t queue = dispatch_queue_create("io_queue", DISPATCH_QUEUE_SERIAL);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
close(fd);
});
long long fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil].fileSize;
NSMutableData *totalData = [[NSMutableData alloc] init];
dispatch_group_t group = dispatch_group_create();
size_t offset = 1024;
for (off_t currentSize = 0; currentSize <= fileSize; currentSize += offset) {
dispatch_group_enter(group);
//io类型为DISPATCH_IO_STREAM时 不用设置off_t offset属性
dispatch_io_read(io, 0, offset, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (error == 0) {
size_t len = dispatch_data_get_size(data);
if (len > 0) {
[totalData appendData:(NSData *)data];
}
}
if (done) {
dispatch_group_leave(group);
}
});
}
dispatch_group_notify(group, queue, ^{
UIImage *image = [UIImage imageWithData:totalData];
NSLog(@"%f %f", image.size.width, image.size.height);
});