在Linux上要獲取進程的信息,需要讀取/proc/進程id/中的文件,如果只是讀一個進程還好,如果要讀取很多進程,或者說像進程管理器一樣要獲取所有進程的信息就有點麻煩了。總不能按1-1000一個一個的遍歷,效率太低。此時可以使用Linux中對目錄進行操作的函數opendir(),readdir()。
轉自http://www.liweifan.com/2012/05/13/linux-system-function-files-operation/
首先說說DIR這一結構體,以下為DIR結構體的定義:
struct __dirstream { void *__fd; char *__data; int __entry_data; char *__ptr; int __entry_ptr; size_t __allocation; size_t __size; __libc_lock_define (, __lock) }; typedef struct __dirstream DIR;
DIR結構體類似於FILE,是一個內部結構,以下幾個函數用這個內部結構保存當前正在被讀取的目錄的有關信息(摘自《UNIX環境高級編程(第二版)》)。函數 DIR *opendir(const char *pathname),即打開文件目錄,返回的就是指向DIR結構體的指針,而該指針由以下幾個函數使用:
struct dirent *readdir(DIR *dp); void rewinddir(DIR *dp); int closedir(DIR *dp); long telldir(DIR *dp); void seekdir(DIR *dp,long loc);
關於DIR結構,我們知道這么多就可以了,沒必要去再去研究他的結構成員。
接着是dirent結構體,首先我們要弄清楚目錄文件(directory file)的概念:這種文件包含了其他文件的名字以及指向與這些文件有關的信息的指針(摘自《UNIX環境高級編程(第二版)》)。從定義能夠看出,dirent不僅僅指向目錄,還指向目錄中的具體文件,readdir函數同樣也讀取目錄下的文件,這就是證據。以下為dirent結構體的定義:
struct dirent { long d_ino; /* inode number 索引節點號 */ off_t d_off; /* offset to this dirent 在目錄文件中的偏移 */ unsigned short d_reclen; /* length of this d_name 文件名長 */ unsigned char d_type; /* the type of d_name 文件類型 */ char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最長255字符 */ }
然后是怎么使用它讀取進程信息。可以用這些函數來讀取/proc下的文件夾,然后做一個判斷,只要文件夾的名字開頭是1-9的,就進入目錄讀取其中的status文件,然后輸出信息。
代碼
#include <stdio.h> #include <dirent.h> #include <unistd.h> #include <stdlib.h> typedef struct{ pid_t pid; char name[256];//進程名稱 int vmsize;//虛擬內存信息 }proc_info_st;//保存讀取的進程信息 #define PROC_NAME_LINE 1//名稱所在行 #define PROC_PID_LINE 4//pid所在行 #define PROC_VMSIZE_LINE 12//虛擬內存所在行 #define BUFF_LEN 1024 //行緩沖區的長度 #ifndef TRUE # define TRUE 1 #endif #ifndef FALSE # define FALSE 0 #endif void read_proc(proc_info_st* info,const char* c_pid);//讀取進程信息 int read_line(FILE* fp,char* buff,int b_l,int l);//讀取一行 int main() { //打開目錄 DIR *dir; struct dirent *ptr; if (!(dir = opendir("/proc"))) return 0; //讀取目錄 while (ptr = readdir(dir)) {//循環讀取出所有的進程文件 if (ptr->d_name[0] > '0' && ptr->d_name[0] <= '9') { //獲取進程信息 proc_info_st info; read_proc(&info,ptr->d_name);//讀取信息 printf("pid:%d\npname:%s\nvmsize:%d\n",info.pid,info.name,info.vmsize); printf("\n\n");//再空兩行 } } } /************************************************** **說明:根據進程pid獲取進程信息,存放在proc_info_st結構體中 ** **輸入: ** /proc_info_st* info 返回進程信息 ** /char* c_pid 進程pid的字符串形式 ** ** ** *************************************************/ void read_proc(proc_info_st* info,const char* c_pid) { FILE* fp = NULL; char file[512] = {0}; char line_buff[BUFF_LEN] = {0};//讀取行的緩沖區 sprintf(file,"/proc/%s/status",c_pid);//讀取status文件 if (!(fp = fopen(file,"r"))) { printf("read %s file fail!\n",file); return; } char name[32]; //先讀取進程名稱 if (read_line(fp,line_buff,BUFF_LEN,PROC_NAME_LINE)) { sscanf(line_buff,"%s %s",name,(info->name)); } fseek(fp,0,SEEK_SET);//回到文件頭部 //讀取進程pid if (read_line(fp,line_buff,BUFF_LEN,PROC_PID_LINE)) { sscanf(line_buff,"%s %d",name,&(info->pid)); } fseek(fp,0,SEEK_SET);//回到文件頭部 //讀取進程vmsize if (read_line(fp,line_buff,BUFF_LEN,PROC_VMSIZE_LINE)) { sscanf(line_buff,"%s %d",name,&(info->vmsize)); } fclose(fp); } /************************************************** **說明:讀取文件的一行到buff ** **輸入: ** /FILE* fp 文件指針 ** /char* buff 緩沖區 ** /int b_l 緩沖區的長度 ** /l 指定行 ** **輸出: ** /true 讀取成功 ** /false 讀取失敗 *************************************************/ int read_line(FILE* fp,char* buff,int b_l,int l) { if (!fp) return FALSE; char line_buff[b_l]; int i; //讀取指定行的前l-1行,轉到指定行 for (i = 0; i < l-1; i++) { if (!fgets (line_buff, sizeof(line_buff), fp)) { return FALSE; } } //讀取指定行 if (!fgets (line_buff, sizeof(line_buff), fp)) { return FALSE; } memcpy(buff,line_buff,b_l); return TRUE; }
