本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
由于各种原因,总有需求想监听文件夹的变化
实现
实际上Android或者linux提供了inotify接口同来监听文件夹变化
提供了poll或者epoll来轮询fd
参考代码
自己写的参考代码如下
int monitorfd; //监听的fd
int watcher;
int epollfd; //用epoll来轮询事件
struct epoll_event event;
struct epoll_event events[2];
FILE* fp;
monitorfd = inotify_init(); //初始化监听的fd
if (-1 == monitorfd) {
ALOGE("inotify_init error");
return;
}
//把文件夹添加进监听器,例如需要监听"/sdcard/"
watcher = inotify_add_watch(monitorfd, "/sdcard/", IN_ALL_EVENTS);
if (-1 == watcher) {
ALOGE("inotify_add_watch error");
return;
}
//打开监听的fd 准备读取事件
fp = fdopen(monitorfd, "r");
if (NULL == fp) {
ALOGE("fdopen error");
return;
}
event.data.fd = monitorfd;
event.events = EPOLLIN | EPOLLET; //读入,边缘触发方式
int ctrl = epoll_ctl(epollfd, EPOLL_CTL_ADD, monitorfd, &event);
if (-1 == ctrl) {
ALOGE("epoll_ctl error");
return;
}
while (1) {//死循环等待epoll轮询到事件处理
int n = epoll_wait(epollfd, events, 5, -1);
for (int i = 0; i < n; i++) {//遍历epoll到的N个事件
ALOGI("%d, %d, %d", events[i].data.fd, monitorfd, events[i].events);
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) {//如果事件不符合预期(EPOLLERR,EPOLLHUP,!EPOLLIN)则关闭句柄后继续轮询
/* An error has occured on this fd, or the socket is not
ready for reading (why were we notified then?) */
ALOGE("epoll error\n");
close(events[i].data.fd);
continue;
} else if (monitorfd == events[i].data.fd) {//如果轮询到的事件的句柄,是监听的句柄,则继续
struct inotify_event ie;
int read_len = 0;
while (1) {
read_len = fread(&ie, sizeof(ie), 1, fp);//读取轮询到的事件的详细信息
if (read_len < 0) {
ALOGD("read error %d:%s\n", errno, strerror(errno));
break;
}
//打印log
ALOGD("%d, %0x, %d\n", ie.wd, ie.mask, ie.len);
if (ie.len > 0) {//如果轮询到的事件的长度大于0,说明事件是有效事件,则继续往下
char name[ie.len];
//读取轮询到的事件的名字
read_len = fread(name, ie.len, 1, fp);
if (read_len > 0) {
//如果读取到的名字大于0,说明读取成功,则根据文件名,拼接文件路径,判断是普通文件,还是文件夹,或者根据需要做一些其他操作,例如是否是自己需要的配置文件等
//somethine to do
}
}
}
}
}
}