调度源阅读器 - 如何检测文件结尾?

发布于 2024-10-31 07:31:10 字数 1505 浏览 0 评论 0原文

灵感来自 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);

Inspired by Apple's documentation, I'm experimenting with using a GCD dispatch source to read asynchronously from a file, instead of using the traditional NSInputStream and run loop based approach.

However, I'm not sure how to detect when I'm done reading the file. With NSInputStream, your delegate get sent a NSStreamEventEndEncountered event. For dispatch sources, I assumed the event handler would get called at the end-of-file, but this doesn't seem to be the case. What am I missing?

Here's my code:

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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

衣神在巴黎 2024-11-07 07:31:10

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

此外,GCD 调度源使用带有 EVFILT_READ 的 kqueue,因此对于常规文件来说并不是很有用。我建议您使用打开/lseek/读取/关闭全局队列中的文件。

  • 回复:文件上的 kqueue 和 EVFILT_READ< /p>

    <块引用>

    在大多数情况下,读取过滤器对于常规文件来说并不是真正有用,因为 - 嗯 - 它们总是可读的,只要它们中保留有数据,并且它们会给出明确的 EOF 条件。您不能真正将文件视为管道 - 即,不要期望 fp 位于 EOF 的文件然后会扩展,以便文件中存在更多数据以导致 EVFILT_READ 变为现实。这适用于非 EV_POLL 情况下的常规文件,但不适用于特殊文件。

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

AFAIK, you have to compare read bytes with the length of the file.

Besides, GCD dispatch source uses kqueue with EVFILT_READ, thus it is not really useful for regular files. I recommend you to use open/lseek/read/close a file in Global Queue.

  • Re: kqueue and EVFILT_READ on files

    For the most part, read filters are not really useful for regular files, since - well - they are always readable, so long as they have data remaining in them, and they will give a clear EOF condition. You can't really treat files as if they were pipes - i.e. don't expect a fle whose fp is at EOF that then gets extended so there is more data in the file to result in an EVFILT_READ coming true. This will work in the non-EV_POLL case, for regular files, but it's not going to work for special files.

    Likewise, at least for most normal block devices (disks, etc.), the are also always readable until you hit the end of the device, and there's a clear EOF indication there, too, so they are not too useful there, either (it's not like more disk blocks will suddenly be arriving on a platter that was built in 1998, for example).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文