调度源阅读器 - 如何检测文件结尾?
灵感来自 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
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