dispatch io.h

版本: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_waterdispatch_io_set_low_waterdispatch_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);
    });

你可能感兴趣的:(dispatch io.h)