linux下根据文件描述符获取出文件描述符所指向的文件名

因为项目中一个小需求要从一个文件描述符中获取出文件描述符所指向的文件名

本来可以在接口中把文件描述符和文件名一起封装成一个结构来返回

但因为在别的地方也会这种应用,所以就想单独把从文件描述符获取文件名做成一个能用接口来使用

本接口只能在linux系统下使用,因为linux系统下所有的东西都可以当成文件来使用

主要使用了lsof指令来实现

lsof常用参数
lsof 常见的用法是查找应用程序打开的文件的名称和数目。可用于查找出某个特定应用程序将日志数据记录到何处,或者正在跟踪

某个问题。例如,linux限制了进程能够打开文件的数目。通常这个数值很大,所以不会产生问题,并且在需要时,应用程序可以请

求更大的值(直到某个上限)。如果你怀疑应用程序耗尽了文件描述符,那么可以使用 lsof 统计打开的文件数目,以进行验证。

lsof语法格式是:

lsof [options] filename
常用的参数列表:

lsof  filename 显示打开指定文件的所有进程
lsof -a 表示两个参数都必须满足时才显示结果
lsof -c string   显示COMMAND列中包含指定字符的进程所有打开的文件
lsof -u username  显示所属user进程打开的文件
lsof -g gid 显示归属gid的进程情况
lsof +d /DIR/ 显示目录下被进程打开的文件
lsof +D /DIR/ 同上,但是会搜索目录下的所有目录,时间相对较长
lsof -d FD 显示指定文件描述符的进程
lsof -n 不将IP转换为hostname,缺省是不加上-n参数
lsof -i 用以显示符合条件的进程情况
lsof -i[46] [protocol][@hostname|hostaddr][:service|port]
            46 --> IPv4 or IPv6
            protocol --> TCP or UDP
            hostname --> Internet host name
            hostaddr --> IPv4地址
            service --> /etc/service中的 service name (可以不只一个)
            port --> 端口号 (可以不只一个)
lsof指令输出格式如下:COMMAND     PID    USER   FD      TYPE     DEVICE     SIZE       NODE NAME
init          1    root  cwd       DIR        3,3     4096          2 /
init          1    root  rtd       DIR        3,3     4096          2 /
init          1    root  txt       REG        3,3    34352   13959233 /sbin/init
init          1    root  mem       REG        3,3   126648    9831535 /lib/ld-2.3.5.so
init          1    root  mem       REG        3,3  1489572    9831536 /lib/libc-2.3.5.so
init          1    root  mem       REG        3,3    81284    9830507 /lib/libsepol.so.1
init          1    root  mem       REG        3,3    68864    9831549 /lib/libselinux.so.1
init          1    root  mem       REG        0,0                   0 [heap] (stat: No such file or directory)
init          1    root   10u     FIFO       0,13                1887 /dev/initctl
syslogd    1584    root    2w      REG        3,3   438824    1574198 /var/log/messages
syslogd    1584    root    3w      REG        3,3     1581    1574338 /var/log/secure
syslogd    1584    root    4w      REG        3,3     1678    1574346 /var/log/maillog
syslogd    1584    root    5w      REG        3,3    10907    1574315 /var/log/cron
syslogd    1584    root    6w      REG        3,3        0    1574365 /var/log/spooler
syslogd    1584    root    7w      REG        3,3        0    1574363 /var/log/boot.log
syslogd    1584    root    8w      REG        3,3        0    1606423 /var/log/news/news.crit
syslogd    1584    root    9w      REG        3,3        0    1606424 /var/log/news/news.err
每行显示一个打开的文件,若不指定条件默认将显示所有进程打开的所有文件。lsof输出各列信息的意义如下: COMMAND:进程的名


PID:进程标识符
USER:进程所有者
FD:文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等
TYPE:文件类型,如DIR、REG等
DEVICE:指定磁盘的名称
SIZE:文件的大小
NODE:索引节点(文件在磁盘上的标识)
NAME:打开文件的确切名称

我们所关注的主要就是 FD列和NAME列
可以用 lsof -d 8
有如下结果
syslogd    1584   root    8w   REG        3,3     0  1606423 /var/log/news/news.crit

可以看到文件描述符8对应的文件为 /var/log/news/news.crit
在代码中,我们可以用popen来把这个指令的结果存到一个FILE的文件中
然后按照一般文件操作方法来进行处理
先用fgets 来读出一整行数据
再用strtok 来把各个列的数据给读出来,直到取到NAME列数据
这就是我们需要的数据了
 
以上只是本人提供的一个思路,希望能对读到此文的朋友有点帮助

 

char s[100] = { 0 };
snprintf(s, 100, "/proc/%d/fd/%d", getpid(), fd);
char name[100] = { 0 };
nRet = readlink(s, name, sizeof(name));
这样也不错

 

 

 

 

On certain systems (see below) you can count them in /proc/[pid]/fd. If not on one of those, see below for:wallyk's answer.

In c, you can list the dir and count the total, or list the dir contents:

 #include <stdio.h> 
 #include <sys/types.h> 
 #include <dirent.h> 
 
 int 
 main (void) 
 { 
   DIR *dp; 
   struct dirent *ep; 
 
   dp = opendir ("/proc/MYPID/fd/"); 
   if (dp != NULL) 
     { 
       while (ep = readdir (dp)) 
         puts (ep->d_name); 
       (void) closedir (dp); 
     } 
   else 
     perror ("Couldn't open the directory"); 
 
   return 0; 
 } 

In bash, something like:

ls -l /proc/[pid]/fd/ | wc -

Operating systems that support the proc filesystem include, but are not limited to:
Solaris
IRIX
Tru64 UNIX
BSD
Linux (which extends it to non-process-related data)
IBM AIX (which bases its implementation on Linux to improve compatibility)
QNX
Plan 9 from Bell Labs

 

 

 

 

 

现工作中,有这么个需求:当处理一个文件结束后,如果该文件大小不合要求(有可能大小为0),就得将该文件删除,可是在文件处理过程中,只知道文件描述符,于是,就想通过一个已打开的文件描述符得到该描述符对应的文件名。经过查询,得知在系统在/proc/pid/fd下为我们记录了已打开文件的一个符号链接,如是想利用readlink通过这个链接得到对应的文件名,如是有了下面的例子:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(){
FILE *fd=fopen("test.txt","w+");
char s[100]={0};
char name[100]={0};


snprintf(s, 100, "/proc/%d/fd/%d", getpid(), fileno(fd) );
printf("sizeof(name)=%d\n",sizeof(name));
int nRet=readlink(s, name, sizeof(name));

printf("s=%s,name=%s\n",s,name);
fclose(fd);

while(1){};
}

可是结果不是我所希望的,readlink竟然返回-1,errno置22(EINVAL 参数bufsiz 为负数)了。这里很是不解,我所传递的参数sizeof(name)明明是100.可是………………望哪位知晓的指点一二,谢谢!!

 

 

Linux中,可以使用`/proc`文件系统来获取文件描述符对应文件名。 每个进程在`/proc`目录下都有一个与其PID同名的目录。在该目录下,有一个`fd`目录,其中包含了进程打开的文件描述符的符号链接。这些符号链接的名称为文件描述符的数字,指向实际打开的文件。 因此,可以通过读取符号链接的目标来获取文件描述符对应文件名。下面是一个示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { int fd = open("/path/to/file", O_RDONLY); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } char path[256]; snprintf(path, sizeof(path), "/proc/%d/fd/%d", getpid(), fd); char file_name[256]; ssize_t len = readlink(path, file_name, sizeof(file_name) - 1); if (len == -1) { perror("readlink"); exit(EXIT_FAILURE); } file_name[len] = '\0'; printf("File name: %s\n", file_name); close(fd); return 0; } ``` 上述代码中,首先使用`open`函数打开一个文件,然后构造`/proc/{PID}/fd/{file descriptor}`路径,将其存储在`path`数组中。接下来,使用`readlink`函数读取符号链接的目标,并将其存储在`file_name`数组中。最后,打印文件名。 需要注意的是,`readlink`函数返回的文件名可能是相对路径或绝对路径,具体取决于打开文件时使用的路径。如果需要获取绝对路径,可以使用`realpath`函数进行进一步的处理。 另外,这种方法只适用于获取当前进程打开的文件文件名,无法获取其他进程打开的文件名
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值