[英]How can I repeatedly read the same line of a FILE in c?
I want to monitor a file that keeps changing a specific line. 我想监视一个不断更改特定行的文件。 Specifically, I am monitoring a processes memory usage in /proc/[PID]/smaps.
具体来说,我在/ proc / [PID] / smaps中监视进程的内存使用情况。
Right now, I check smaps with: 现在,我使用以下方法检查smap:
fp = popen("/bin/cat /proc/19596/smaps | grep stack --after-context=1", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit;
}
/* Read the output a line at a time - output it. */
while(1){
while (fgets(path, sizeof(path)-1, fp) != NULL) {
printf("%s", path);
}
}
/* close */
pclose(fp);
but this is not updating. 但这没有更新。 How can I keep printing out the lines of the file as they open?
打开文件时,如何继续打印出文件中的行? Do I need to close the file each time or is there a faster way?
我是否需要每次关闭文件,还是有更快的方法?
/proc/
is a Linux specific filesystem made of pseudo-files, which you should access sequentially. /proc/
是由伪文件组成的Linux特定文件系统,您应按顺序访问。 See proc(5) . 参见proc(5) 。
So in practice, you need to reopen that /proc/19596/smaps
file. 因此,在实践中,您需要重新打开
/proc/19596/smaps
文件。 Read it is very quick and does not involve any disk I/O! 读取速度非常快,并且不涉及任何磁盘I / O! It is about as fast as reading from a pipe(7) .
它大约和从pipe(7)读取数据一样快。
You are wrong in using popen
(with a useless use of cat
). 您使用
popen
是错误的(不带cat
用法)。 You should better open (using fopen(3) ) the /proc/19596/smaps
file, loop on reading every line (eg using fgets(3) ), comparing it (using eg strstr(3) ) with "stack"
literal string, and reading the next line, and finally fclose
it immediately after. 您最好打开(使用fopen(3) )
/proc/19596/smaps
文件,循环读取每一行(例如,使用fgets(3) ),并将其与"stack"
文字字符串进行比较(例如,使用strstr(3) ) ,然后阅读下一行,最后立即将其fclose
。
BTW, if your process 19596 happens to have several threads, I am not sure that you are measuring a meaningful stack size. 顺便说一句,如果您的进程19596恰好有多个线程,则我不确定您正在测量有意义的堆栈大小。
Honestly speaking I don't see why you want to do this in C. 老实说,我不明白为什么要在C语言中执行此操作。
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <unistd.h>
enum { ERR = -1 };
static int s_running = 1;
static void sigintHandler(int s) {
(void)s;
s_running = 0;
}
int main(int argc, char *argv[]) {
int pid = -1, sleepMsec = 1000;
char optchr, buf[260];
FILE *fp;
signal(SIGINT, sigintHandler);
while (ERR != (optchr = getopt(argc, argv, "p:s:"))) {
switch (optchr) {
case 'p': pid = strtol(optarg, NULL, 0); break;
case 's': sleepMsec = strtol(optarg, NULL, 0); break;
default:
fprintf(stderr, "USAGE: smap -p pid [-s msec]\n");
return -10;
}
}
snprintf(buf, sizeof buf, "/proc/%d/smaps", pid);
buf[sizeof buf - 1] = '\0';
fp = fopen(buf, "r");
if (NULL == fp) {
char buf1[sizeof buf];
snprintf(buf1, sizeof buf1, "fopen for [%s]", buf);
buf1[sizeof buf1 - 1] = '\0';
perror(buf1);
return -20;
}
for (;;) {
if (ERR == fseek(fp, 0, SEEK_SET)) {
perror("fseek(3)");
return -30;
}
while (fgets(buf, sizeof buf, fp)) {
if (strstr(buf, "stack")) {
printf("%s", buf);
if ( ! fgets(buf, sizeof buf, fp)) {
fprintf(stderr, "fgets(3) found EOF\n");
return -40;
}
printf("%s", buf);
}
}
usleep(1000 * sleepMsec);
if ( ! s_running)
break;
}
printf("Bye!\n");
return 0;
}
I recommend you to use scripting languages such as Python for this kind of task. 我建议您将脚本语言(例如Python)用于此类任务。
#! /usr/bin/env python
from __future__ import print_function
import time
import sys
import getopt
def main(args):
pid = -1
sleepMsec = 1000
opts, _ = getopt.getopt(args, "p:s:")
for (k,a) in opts:
if "-p" == k:
pid = int(a)
elif "-s" == k:
sleepMsec = int(a)
try:
with open("/proc/{}/smaps".format(pid)) as fp:
while True:
fp.seek(0)
while True:
line = fp.readline()
if not line:
break
if 0 <= line.find("stack0"):
print(line, fp.readline(), sep='', end='')
break
time.sleep(1e-3 * sleepMsec)
except KeyboardInterrupt:
print("Bye!")
if "__main__" == __name__:
main(sys.argv[1: ])
Combination of Bash and standard Linux commands is an option, too. 也可以选择将Bash与标准Linux命令结合使用。 Indeed you already used grep for your initial version.
确实,您已经使用grep作为初始版本。
Note that you cannot use fseek(3)
against a pipe (it's a stream in a strict sense) but the /proc/PID/smaps
pseudo-filesystem supports it. 请注意,您不能对管道使用
fseek(3)
(严格意义上讲,它是一个流),但是/proc/PID/smaps
伪文件系统支持它。
Not sure if this works optimally with the files in /proc
but you can use Linux's inotify
system to have the kernel notify you of changes on watched files so that you don't have to poll. 不知道这是否可以与
/proc
的文件配合使用,但是您可以使用Linux的inotify
系统让内核将监视文件的更改通知您,从而使您不必轮询。 You can access the system in C, but trying it out in the shell by using the inotifywait
tool should be a good starting point (the following should be way more efficient than the C code in your question). 您可以使用C语言访问系统,但是使用
inotifywait
工具在shell中进行inotifywait
应该是一个很好的起点(以下内容应比您问题中的C代码更有效)。
pid=19596
file=/proc/$pid/smaps
cmd="grep stack --after-context=1"
while intofitywait -e modify "$file"; do $cmd "$file"; done
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.