Dispatch Source Reader - 如何检测文件结尾?

时间:2011-04-11 12:06:31

标签: c cocoa file-io grand-central-dispatch

Apple's documentation的启发,我正在尝试使用GCD调度源从文件中异步读取,而不是使用传统的NSInputStream和基于循环的方法。

但是,我不知道如何检测我读完文件的时间。使用NSInputStream,您的代理会收到NSStreamEventEndEncountered个活动。对于调度源,我假设事件处理程序将在文件结束时被调用,但似乎并非如此。我错过了什么?

这是我的代码:

const char* fileName = "/Users/Nick/Music/iTunes/iTunes Music Library.xml";
int fd = open(fileName, O_NONBLOCK|O_RDONLY);
assert(fd>0);

dispatch_source_t readerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());

dispatch_source_set_event_handler(readerSource, ^{
    char buffer[1024];
    size_t estimatedLength = dispatch_source_get_data(readerSource);

    ssize_t bytesRead = read(fd, buffer, MIN(1024, estimatedLength));
    if (bytesRead < 0) {
        if (errno != EAGAIN) {
            printf("Unexpected error!");
            abort();
        }
    } else if (bytesRead > 0) {
        printf("Got %ld bytes of data.\n", bytesRead);
    } else {
        // bytesRead == 0
        printf("EOF encountered!\n");
        dispatch_source_cancel(readerSource);
    }
});

dispatch_source_set_cancel_handler(readerSource, ^{
    printf("Cancel handler was called.\n");
    close(fd);
    dispatch_release(readerSource);
});

dispatch_resume(readerSource);

1 个答案:

答案 0 :(得分:1)

AFAIK,您必须将读取的字节与文件的长度进行比较。

此外,GCD调度源使用带有EVFILT_READ的kqueue,因此它对常规文件并不实用。我建议你在Global Queue中使用open / lseek / read / close文件。

  • Re: kqueue and EVFILT_READ on files

      

    在大多数情况下,读取过滤器对常规文件并不是很有用,因为 - 好 - 它们总是可读的,只要它们中有数据,它们就会给出明确的EOF条件。您不能将文件视为管道 - 即不要期望其fp处于EOF的文件然后被扩展,因此文件中有更多数据导致EVFILT_READ成立。对于常规文件,这将适用于非EV_POLL情况,但它不适用于特殊文件。

         

    同样地,至少对于大多数普通的块设备(磁盘等)来说,在你到达设备末端之前,它们总是可读的,并且那里也有清晰的EOF指示,因此它们在那里不太有用,或者(不像更多的磁盘块会突然出现在1998年制造的盘子上)。