最近在做网页爬虫的测试,需要通过apache的access-log来验证爬虫的行为,就想到了用类似linux的tail命令实现方式来实现。这里先把代码贴出来:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/stat.h>
static size_t filesize(const char *filename) {
struct stat sb;
if (!stat(filename, &sb))
return sb.st_size;
return 0;
}
static void tailf(const char *filename, int lines) {
char **buffer;
int head = 0;
int tail = 0;
FILE *str;
int i;
if (!(str = fopen(filename, "r"))) {
fprintf(stderr, "Cannot open \"%s\" for read\n", filename);
perror("");
exit(1);
}
buffer = (char **) malloc(lines * sizeof(*buffer));
for (i = 0; i < lines; i++)
buffer[i] = (char *) malloc(BUFSIZ + 1);
while (fgets(buffer[tail], BUFSIZ, str)) {
if (++tail >= lines) {
tail = 0;
head = 1;
}
}
//the method here is very smart, if variable head is set, that is to say the file is longer than 10 lines,
//and the first line of the last 10 lines is start from the index tail, and the last line is at index tail-1
if (head) {
for (i = tail; i < lines; i++)
fputs(buffer[i], stdout);
for (i = 0; i < tail; i++)
fputs(buffer[i], stdout);
} else {
for (i = head; i < tail; i++)
fputs(buffer[i], stdout);
}
fflush(stdout);
for (i = 0; i < lines; i++)
free(buffer[i]);
free(buffer);
}
int main(int argc, char **argv) {
char buffer[BUFSIZ];
size_t osize, nsize;
FILE *str;
const char *filename;
int count;
if (argc != 2) {
fprintf(stderr, "Usage: tailf logfile\n");
exit(1);
}
filename = argv[1];
tailf(filename, 10);
for (osize = filesize(filename);;) {
nsize = filesize(filename);
if (nsize != osize) {
if (!(str = fopen(filename, "r"))) {
fprintf(stderr, "Cannot open \"%s\" for read\n", filename);
perror(argv[0]);
exit(1);
}
if (!fseek(str, osize, SEEK_SET))
while ((count = fread(buffer, 1, sizeof(buffer), str)) > 0)
fwrite(buffer, 1, count, stdout);
fflush(stdout);
fclose(str);
osize = nsize;
}
usleep(250000); /* 250mS */
}
return 0;
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/stat.h>
static size_t filesize(const char *filename) {
struct stat sb;
if (!stat(filename, &sb))
return sb.st_size;
return 0;
}
static void tailf(const char *filename, int lines) {
char **buffer;
int head = 0;
int tail = 0;
FILE *str;
int i;
if (!(str = fopen(filename, "r"))) {
fprintf(stderr, "Cannot open \"%s\" for read\n", filename);
perror("");
exit(1);
}
buffer = (char **) malloc(lines * sizeof(*buffer));
for (i = 0; i < lines; i++)
buffer[i] = (char *) malloc(BUFSIZ + 1);
while (fgets(buffer[tail], BUFSIZ, str)) {
if (++tail >= lines) {
tail = 0;
head = 1;
}
}
//the method here is very smart, if variable head is set, that is to say the file is longer than 10 lines,
//and the first line of the last 10 lines is start from the index tail, and the last line is at index tail-1
if (head) {
for (i = tail; i < lines; i++)
fputs(buffer[i], stdout);
for (i = 0; i < tail; i++)
fputs(buffer[i], stdout);
} else {
for (i = head; i < tail; i++)
fputs(buffer[i], stdout);
}
fflush(stdout);
for (i = 0; i < lines; i++)
free(buffer[i]);
free(buffer);
}
int main(int argc, char **argv) {
char buffer[BUFSIZ];
size_t osize, nsize;
FILE *str;
const char *filename;
int count;
if (argc != 2) {
fprintf(stderr, "Usage: tailf logfile\n");
exit(1);
}
filename = argv[1];
tailf(filename, 10);
for (osize = filesize(filename);;) {
nsize = filesize(filename);
if (nsize != osize) {
if (!(str = fopen(filename, "r"))) {
fprintf(stderr, "Cannot open \"%s\" for read\n", filename);
perror(argv[0]);
exit(1);
}
if (!fseek(str, osize, SEEK_SET))
while ((count = fread(buffer, 1, sizeof(buffer), str)) > 0)
fwrite(buffer, 1, count, stdout);
fflush(stdout);
fclose(str);
osize = nsize;
}
usleep(250000); /* 250mS */
}
return 0;
}