本质上是一个
tail -f
实现:我正在更新一个在旧系统上运行良好的程序,它将连续读取打开的文件:在EOF之后,等待文件增长并继续读取。在较新的系统上,它无法读取 EOF 之后的文件,我不明白为什么。我删除了所有不相关的代码,并能够使用以下简化示例进行重现,该示例与此处给出的模式几乎相同。
// COMPILE WITH: gcc a.c -o a.out
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
//----------------------------------------------------------------
char* file_path = "/var/log/mail.log"; // any file that's active
int seek_to_head = 0;
int seek_to_tail = 1;
int loop_sleep_seconds = 4;
int use_getline = 1; // if 0, uses fgets()
//----------------------------------------------------------------
size_t line_size_fgets = 1024;
char line_fgets[line_size_fgets];
char* line = NULL;
size_t line_size = 0;
// Open the file
FILE* FILE_HANDLE;
if (!(FILE_HANDLE = fopen(file_path, "r"))) {
printf("Failed to open file [%s]: %s\n", file_path, strerror(errno));
return 1;
}
// Unbuffer input
if (setvbuf(FILE_HANDLE, NULL, _IONBF, 0) != 0)
// if (setvbuf(FILE_HANDLE, NULL, _IOLBF, 0) != 0)
{
printf("Failed to unbuffer\n");
return 1;
}
// Seek to head
if (seek_to_head) {
if (fseek(FILE_HANDLE, 0, SEEK_SET)) {
printf("Failed to seek to beginning of file\n");
return 1;
}
printf("Seek to start of file -- SUCCESS\n");
}
// Seek to tail
if (seek_to_tail) {
if (fseek(FILE_HANDLE, 0, SEEK_END)) {
printf("Failed to seek to end of file\n");
return 1;
}
printf("Seek to end of file -- SUCCESS\n");
}
printf("Begin tracking file %s\n", file_path);
// Main loop
while (1) {
// Read all remaining file contents til exhausted for now
if (use_getline)
while (getline(&line, &line_size, FILE_HANDLE) != -1)
printf("\nLINE: %s\n", line);
else
while (fgets(line_fgets, line_size_fgets, FILE_HANDLE) != NULL)
printf("\nLINE: %s\n", line_fgets);
// Make sure there wasn't an error reading file
if (ferror(FILE_HANDLE)) {
printf("Failed to read from file [%s]: %s\n", file_path, strerror(errno));
return 1;
}
// Pause for file to grow (inotify code goes here)
sleep(loop_sleep_seconds);
printf("Try reading again\n");
}
free(line);
printf("Exiting\n");
return 0;
}
此示例有一个变量,您可以翻转以使用 getline() 或 fgets(),但在我尝试过的较新系统上,两者都存在相同的问题。如果查找文件的开头,则会打印迄今为止的所有文件内容,但不会打印此后的任何内容。如果查找到文件末尾,则不会产生任何输出。真正的程序轮询文件更改而不是休眠,我确认轮询工作正常,但这似乎无关;两种方式的错误行为都是相同的。我错过了一些明显的东西吗?
// Pause for file to grow (inotify code goes here)
if( feof( FILE_HANDLE ) )
{
clearerr( FILE_HANDLE ) ;
sleep(loop_sleep_seconds);
printf("Try reading again\n");
}
否则 EOF 通常只能通过调用同一流上的 rewind、fseek、fsetpos 和 freopen 之一来清除。因此您可以选择 或 setpos
到当前位置。