3

Apple 文档的启发,我正在尝试使用 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);
4

1 回答 1

2

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

此外,GCD 调度源使用带有 EVFILT_READ 的 kqueue,因此对于常规文件并没有真正的用处。我建议您在全局队列中使用 open/lseek/read/close 文件。

  • 回复:文件上的 kqueue 和 EVFILT_READ

    在大多数情况下,读取过滤器对常规文件并没有真正的用处,因为——好吧——它们总是可读的,只要它们有剩余的数据,并且它们会给出一个明确的 EOF 条件。您不能真正将文件视为管道 - 即不要指望其 fp 位于 EOF 的文件随后会被扩展,因此文件中有更多数据会导致 EVFILT_READ 变为真。这适用于非 EV_POLL 情况,适用于常规文件,但不适用于特殊文件。

    同样,至少对于大多数普通的块设备(磁盘等)来说,它们也始终是可读的,直到你到达设备的末尾,并且那里也有一个明确的 EOF 指示,所以它们在那里也不太有用(例如,在 1998 年制造的盘片上不会突然有更多的磁盘块)。

于 2011-05-06T07:53:09.930 回答