文章目录
- 0. 概述
- 1. `select` 函数概述
- 2. 普通文件描述符的 `select` 行为
- 3. 监控普通文件描述符的实际应用
- 3.1 C++ 代码示例
- 3.2 使用 `stat` 函数监控文件修改时间
- 结论
0. 概述
在编程中,select
函数可以用于监控多个文件描述符(包括 socket、串口和普通文件),以等待它们变为可读、可写或发生错误事件。本文将重点介绍 select
在监控普通文件描述符(句柄)时的行为,并提供实际的 C++ 代码示例。
1. select
函数概述
select
是一个系统调用函数,用于监控多个文件描述符,等待它们变为可读、可写或发生错误事件。调用 select
时,程序会阻塞,直到至少有一个描述符满足指定条件或超时。
2. 普通文件描述符的 select
行为
对于普通文件描述符,select
的行为与 socket 或串口略有不同:
- 普通文件是否可读主要依赖于文件的当前读取位置以及文件的实际内容。
- 如果一个普通文件已经打开且没有到达文件尾(EOF),
select
会将其标记为可读状态。 - 一旦文件被读取到 EOF,之后的
select
调用(若没有新的数据写入文件)将不会将其标记为可读,除非文件被重新写入或文件指针被重置。
3. 监控普通文件描述符的实际应用
3.1 C++ 代码示例
以下是一段 C++ 代码,演示了如何使用 select
监控一个普通文件。当文件内容发生变化时,程序会调用 onFileChange
回调函数:
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include <iostream>
#include <vector>static off_t lastReadPosition = 0;void onFileChange(FILE* file);int main() {const char* filePath = "/home/feng/workspace/test_select_file/example.txt";FILE* file = fopen(filePath, "r");if (!file) {perror("无法打开文件");return 1;}int fileFd = fileno(file);if (fileFd == -1) {perror("无法获取文件描述符");fclose(file);return 1;}fd_set rfds;FD_ZERO(&rfds);FD_SET(fileFd, &rfds);struct timeval tv = {1, 0};while (true) {fd_set rfdsCopy = rfds;int retval = select(fileFd + 1, &rfdsCopy, nullptr, nullptr, &tv);if (retval == -1) {perror("select failed");break;} else if (retval) {if (FD_ISSET(fileFd, &rfdsCopy)) {fseek(file, 0, SEEK_END);onFileChange(file);}}}fclose(file);return 0;
}void onFileChange(FILE* file) {off_t currentPosition = ftell(file);if (currentPosition != lastReadPosition) {std::cout << "文件内容发生变化,触发回调函数!" << std::endl;lastReadPosition = currentPosition;}
}
这段代码通过 select
函数监控文件描述符的变化,当文件内容发生变化时,调用 onFileChange
函数进行处理。
3.2 使用 stat
函数监控文件修改时间
另一个示例展示了如何使用 stat
函数监控文件的最后修改时间:
#include <sys/stat.h>
#include <unistd.h>
#include <ctime>
#include <iostream>void printLastModificationTime(const char* filePath) {struct stat fileStats;if (stat(filePath, &fileStats) == 0) {std::cout << "File: " << filePath << " last modified at: " << std::asctime(std::localtime(&fileStats.st_mtime));} else {perror("Error getting file status");}
}int main() {const char* filePath = "/tmp/example.txt";printLastModificationTime(filePath);std::cout << "Watching for changes...\n";while (true) {sleep(1);struct stat currentStats;if (stat(filePath, ¤tStats) == 0) {time_t currentTime = currentStats.st_mtime;static time_t previousTime = currentTime;if (currentTime != previousTime) {std::cout << "File modified! New time: ";printLastModificationTime(filePath);previousTime = currentTime;}} else {perror("Error in stat during watch");break;}}return 0;
}
结论
本文介绍了如何使用 select
函数监控普通文件描述符,并提供了实际的 C++ 代码示例,展示了文件内容变化检测和文件最后修改时间监控的实现方法。