Linux-文件IO

当程序执行标准库函数printf时,会用到文件指针FILE *stdout。
stdout主要由三部分构成,如下图。
在这里插入图片描述
stdout实际就对应文件描述符中的1。
执行标准库函数printf时,程序会调用内核提供的系统调用函数write。
在这里插入图片描述
我们针对一个文件的操作可以规定为这5个操作:open、close、read、write、lseek

open、close、read、write、lseek

open

因为他们都属于系统调用,所以在查看时要加上2,表示查看第二章的。
比如查看第二章open的使用方法,man 2 open
在这里插入图片描述
在这里插入图片描述
参数:

pathname:文件名
flags,
必选项
O_RDONLY, O_WRONLY, or O_RDWR.
可选项
O_APPEND 追加

O_CREAT (文件不存在时)创建
O_EXCL必须和O_CREAT一起使用,(如果文件存在则报错。)
mode:权限位
mode指定创建新文件时使用的权限。
当O_CREAT或O_TMPFILE在flags中指定时必须提供此参数;如果没有指定O_CREAT和O_TMPFILE,则忽略mode。
最终(mode & ~umask)

O_NONBLOCK 非阻塞

必选项和可选项实际上是一个32位的位图在这里插入图片描述
返回值
在这里插入图片描述
成功返回当前最小的可用的文件描述符。失败返回-1.
在这里插入图片描述
默认一个进程启动之后,0、1、2是被使用的,对应标准输入、标准输出和标准错误,此时再打开一个文件,将返回的文件描述符是3。
如果把0,1,2的其中一个或多个给关闭了,则返回被关的最小的那个文件描述符。

close

同样查看open的使用方法,man 2 close
在这里插入图片描述
参数:open打开的文件描述符。
在这里插入图片描述
返回值:成功返回0,失败返回-1.

使用open和close函数实现touch命令的部分功能(打开或新建一个文件,并指定权限。)

//printf需要用
#include <stdio.h>
//open需要用
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//close需要用
#include <unistd.h>

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("%s filename.\n",argv[0]);
        return -1;
    }
    int fd = open(argv[1],O_RDONLY|O_CREAT,0666);
    //0666&(~umask) = 0666&(~0002)=0666&7775=0665,rw- rw- r-x,因为是文件,所以x也会被拿走,最后是rw- rw- r--
    close(fd);

    return 0;
}

运行代码:
在这里插入图片描述
只读打开一个名为creat_test的文件,如果文件不存在就创建它,指定权限为rw- rw- r–

read

在这里插入图片描述
从fd中最多读count字节。
read是阻塞等待的

write

在这里插入图片描述

实现一个cat功能

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("%s filename\n",argv[0]);
        return -1;
    }

    int fd = open(argv[1],O_RDONLY);

    //读,输出到屏幕
    char buf[256];
    int ret=0;
    do
    {
    	//从fd中读,读到buf中,最多读sizeof(buf)个字节。
    	//fd会递增的,最终指向文件末尾
        ret=read(fd,buf,sizeof(buf));
        //测试是否不管文件中还剩多少字节,每次都读count
        printf("%d\n",ret);//测出的结果是有多少读多少,最多读到count.
        //STDOUT_FILENO是标准输出的宏定义,值为1
        write(STDOUT_FILENO,buf,ret);
    }while(ret>0&&ret==sizeof(buf));//代表读到末尾了

    close(fd);

    return 0;
}

lseek实现文件读写位置改变

需求:打开一个文件,写入内容:helloworld,然后读取下该文件的内容,输出到屏幕。
先来实现下。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("%s filename\n",argv[0]);
        return -1;
    }

    char str[]="hello world";

    int fd = open(argv[1],O_RDWR|O_CREAT,0666);

        //STDOUT_FILENO是标准输出的宏定义,值为1
    write(fd,str,sizeof(str));

    //读,输出到屏幕
    char buf[256];
    memset(buf,0,sizeof(buf));
    int ret=0;
    do
    {
        ret=read(fd,buf,sizeof(buf));
        printf("%d\n",ret);
        //STDOUT_FILENO是标准输出的宏定义,值为1
	        write(STDOUT_FILENO,buf,ret);
    }while(ret>0&&ret==sizeof(buf));

    close(fd);

    return 0;
}

运行一下:
在这里插入图片描述
原因出在哪呢?为什么没有输出出来呢?
有没有写到my_lseek.log这个文件中呢?
打开my_lseek.log这个文件看下。
在这里插入图片描述
写进去了。
那为什么呢?
是因为在write之后,读写文件指针 fd 移动到文件末尾了,如果我们要想输出出内容,就必须将读写文件指针 fd 移动到开头,这需要用到一个函数lseek。
看下lseek这个函数。
在这里插入图片描述
在这里插入图片描述
函数的作用是:根据下面的指令,将与文件描述符fd关联的打开文件的偏移量重新定位到参数offset上:
在这里插入图片描述
返回值
成功:返回当前位置到开始位置的偏移的字节数。
失败:返回 -1。
在上述代码中添加:

lseek(fd,0,SEEK_SET);

lseek实现文件读写位置改变

验证Linux能够打开文件的最大数量

Linux能够打开的最大文件数量为1024(文件描述符为0-1023)个。
在这里插入图片描述
默认一个进程启动之后,0、1、2是被使用的,对应标准输入、标准输出和标准错误,此时再打开一个文件,将返回的文件描述符是3。

因为这里的主要目的是验证能打开多少文件,所以就不关闭文件描述符,正常来说是要打开一个文件关闭一个文件的。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


//验证Linux能打开的最大文件数量
int main()
{
    //默认再打开的文件是从3开始的
    //前面三个已打开的文件分别是标准输入、标准输出、标准错误
    int num = 3;
    int count = 0;
    char filename[128];
    while(1)
    {
        sprintf(filename,"temp_%04d",num++);
        if(open(filename,O_RDONLY|O_CREAT,0666) < 0 )
        {
            perror("open error");
            break;
        }
        else
        {
            //open sucess
            count += 1;
        }
    }

    printf("count = %04d.\n",count);

    return 0;
}

程序运行输出结果如下:
在这里插入图片描述

stat函数

获得文件信息
在这里插入图片描述

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *buf);
//通过一个文件名获取文件属性
int fstat(int fd, struct stat *buf);
//通过一个已经打开的文件描述符来获取文件的属性
int lstat(const char *pathname, struct stat *buf);
//可以发现与stat的参数和返回值都相同,但这个函数前面加上了一个字母l,说明这个函数与stat在处理链接文件有不同的之处。

我们使用 ls -l 实现的也是查看文件的详细信息,因此使用这个函数可以实现相同的功能。

函数参数:

const char *pathname, //文件名
struct stat *buf //一个指向struct stat结构体的指针,是传出参数

返回值:

On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

主要看下这个struct stat结构体。

struct stat {
dev_t     st_dev;         /* ID of device containing file */包含该文件的设备号ID
ino_t     st_ino;         /* inode number */文件的索引节点
mode_t    st_mode;        /* protection */ 文件类型和权限
nlink_t   st_nlink;       /* number of hard links */硬连接数量
uid_t     st_uid;         /* user ID of owner */用户的ID
gid_t     st_gid;         /* group ID of owner */ID
dev_t     st_rdev;        /* device ID (if special file) */
off_t     st_size;        /* total size, in bytes */文件大小
blksize_t st_blksize;     /* blocksize for filesystem I/O */块的大小
blkcnt_t  st_blocks;      /* number of 512B blocks allocated */块的个数

/* Since Linux 2.6, the kernel supports nanosecond
   precision for the following timestamp fields.
   For the details before Linux 2.6, see NOTES. */

struct timespec st_atim;  /* time of last access */上一次的访问时间
struct timespec st_mtim;  /* time of last modification */上一次的修改时间
struct timespec st_ctim;  /* time of last status change *//上一次的状态变化的时间

#define st_atime st_atim.tv_sec      /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};

说一说这个结构体的一些成员变量

1、st_ino; // inode number

inode是index node,表示索引结点,里面有文件存储在磁盘的哪个位置的信息,以及文件大小、时间等等信息。
在这里插入图片描述
2、st_mode; // 文件类型和权限

判断文件类型可以根据掩码值。其中,第一位的0表示八进制。
也就是说,7代表二进制的111.
在这里插入图片描述
如果不想使用掩码这种处理方式,还可以使用下面的几种宏。
在这里插入图片描述
此外,还有几位数分别用来表示特殊的权限位和三类人的权限。

比如下图中的第一位表示特殊的权限位(很少使用)和另外三位数则表示三类人的权限。

同样都是八进制数。
在这里插入图片描述
在这里插入图片描述
3、再来说一说这个结构体成员变量中的数据类型 struct timespec

先来说一说怎么找这个结构体
假设一开始并不知道这个结构体在哪?只知道有这个结构体名。
那么就可以在根目录中使用grep -rn来搜索。

-r代表递归查找,-n代表显示行号。
此外,找结构体时,有技巧,就是在结构体类型名后加上{,还有就是一般都在/usr目录下。

grep -rn "struct timespec {" /usr/

查找比较慢,需要耐心等待。
在这里插入图片描述
应该是在

/usr/include/linux/time.h:9:struct timespec {

打开查找到的文件。
使用命令
在这里插入图片描述
其中的+9表示可以定位到改行。

struct timeval {
     __kernel_time_t     tv_sec;     /* seconds */
     __kernel_suseconds_t    tv_usec;    /* microseconds */
 };

在这里插入图片描述
除了stat这个函数之外呢,还有stat这个命令。

比如使用stat这个命令来查看daemon.c这个文件的详细信息,就可以使用命令stat daemon.c

输出结果如下:
在这里插入图片描述

应用stat函数–实现ls命令

实现目标:
在这里插入图片描述
实现目标:

获取文件用户的相关信息 – getpwuid

需要传入uid_t uid

#include <sys/types.h>
#include <pwd.h>

struct passwd *getpwuid(uid_t uid);

返回值是struct passwd类型的值

The passwd structure is defined in <pwd.h> as follows:

struct passwd {
   char   *pw_name;       /* username */
   char   *pw_passwd;     /* user password */
   uid_t   pw_uid;        /* user ID */
   gid_t   pw_gid;        /* group ID */
   char   *pw_gecos;      /* user information */
   char   *pw_dir;        /* home directory */
   char   *pw_shell;      /* shell program */
};

获取文件组的相关信息 – getgrgid

需要传入gid_t gid

#include <sys/types.h>
#include <grp.h>

struct group *getgrgid(gid_t gid);

返回值是struct group 类型的值

The group structure is defined in <grp.h> as follows:

struct group {
       char   *gr_name;        /* group name */
       char   *gr_passwd;      /* group password */
       gid_t   gr_gid;         /* group ID */
       char  **gr_mem;         /* NULL-terminated array of pointers
                                          to names of group members */
};

时间获取 – localtime

需要传入const time_t * timep

#include <time.h>

struct tm *localtime(const time_t *timep);

返回值是struct tm 类型的值

Broken-down time is stored in the structure tm, which is defined in <time.h> as follows:

struct tm {
  int tm_sec;    /* Seconds (0-60) */
  int tm_min;    /* Minutes (0-59) */
  int tm_hour;   /* Hours (0-23) */
  int tm_mday;   /* Day of the month (1-31) */
  int tm_mon;    /* Month (0-11) */
  int tm_year;   /* Year - 1900 */
  int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
  int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
  int tm_isdst;  /* Daylight saving time */
};

具体的实现代码如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
//-rw-rw-r-- 1 book book 1353 8月  17 17:31 daemon.c

void file_type(struct stat m,char *buf)
{
    if(S_ISREG(m.st_mode))  //is it a regular file?
        buf[0]='-';
    else if(S_ISDIR(m.st_mode)) //  directory?
        buf[0]='d';
    else if(S_ISCHR(m.st_mode)) // character device?
        buf[0]='c';
    else if(S_ISBLK(m.st_mode))  //block device?
        buf[0]='b';
    else if(S_ISFIFO(m.st_mode)) //FIFO (named pipe)?
        buf[0]='p';
    else if(S_ISLNK(m.st_mode))  //symbolic link?  (Not in POSIX.1-1996.)
        buf[0]='l';
    else if(S_ISSOCK(m.st_mode))  //symbolic link?  (Not in POSIX.1-1996.)
        buf[0]='s';
}

void file_permission(struct stat m,char* buf)
{
    if(m.st_mode & S_IRUSR)
        buf[1]='r';

    if(m.st_mode & S_IWUSR)
        buf[2]='w';

    if(m.st_mode & S_IXUSR)
        buf[3]='x';

    if(m.st_mode & S_IRGRP)
        buf[4]='r';
        
	if(m.st_mode & S_IWGRP)
        buf[5]='w';

    if(m.st_mode & S_IXGRP)
        buf[6]='x';

    if(m.st_mode & S_IROTH)
        buf[7]='r';

    if(m.st_mode & S_IWOTH)
        buf[8]='w';

    if(m.st_mode & S_IXOTH)
        buf[9]='x';
}

//时间获取
struct tm *get_FileAcessTime(const time_t *timep)
{
    struct tm *get_FileTime = localtime(timep);
    return get_FileTime;
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("./%s filename.\n",argv[0]);
        return -1;
    }
    //调用stat 得到文件属性信息
    struct stat sb;
    stat(argv[1],&sb);

  //获取文件类型信息和文件权限信息,并保存到数组中
    char stmode[11];
    memset(stmode,'-',sizeof(stmode));
    //文件类型
    file_type(sb,stmode);
	//文件权限位
    file_permission(sb,stmode);
    stmode[10]='\0';

    //硬连接数量--可通过struct stat来获得
    //文件用户名--可通过函数getpwuid来获得
    //文件组用户名--可通过函数getgrgid来获得
    //文件大小--可直接通过struct stat来获得
    //时间可通过函数localtime来获取
    
    //获取文件的时间信息,并保存到数组中
    char timebuf[20];
    struct tm *get_Time = get_FileAcessTime(&sb.st_atim.tv_sec);
    sprintf(timebuf,"%d月  %d %d:%d",get_Time->tm_mon+1,get_Time->tm_mday,get_Time->tm_hour,get_Time->tm_min);

 //-rw-rw-r-- 1 book book 1353 8月  17 17:31 daemon.c
    printf("%s %lu %s %s %lu %s %s\n",stmode,sb.st_nlink,getpwuid(sb.st_uid)->pw_name,getgrgid(sb.st_gid)->gr_name,sb.st_size,timebuf,argv[1]);

    return 0;
}

程序运行结果并验证:
在这里插入图片描述

access

功能:判断当前用户对该文件的权限以及文件是否存在。

#include <unistd.h>

int access(const char *pathname, int mode);

mode:
R_OK(是否有读权限), W_OK(是否有写权限), and X_OK(是否有可执行权限).  F_OK(文件是否存在)

返回值:
如果有对应权限或文件存在,则返回0.
失败返回-1,并设置errno.
#include <stdio.h>
#include <unistd.h>

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("%s filename.\n",argv[0]);
        return -1;
    }

    if(access(argv[1],F_OK)==0)
    {
        printf("%s Find ok.\n",argv[1]);

        if(access(argv[1],R_OK)==0)
        {
            printf("%s read ok.\n",argv[1]);
        }
        else
        {
            perror("read error");
        }

        if(access(argv[1],W_OK)==0)
        {
            printf("%s write ok.\n",argv[1]);
        }
        else
        {
            perror("write error");
        }
        
		if(access(argv[1],X_OK)==0)
        {
            printf("%s excute ok.\n",argv[1]);
        }
        else
        {
            perror("execute error");
        }
      }
     else
     {
        perror("no find");
     }

    return 0;
}

程序运行结果如下:
在这里插入图片描述
文件所属为book用户,当前在book用户下,所以看用户对应的读写可行性权限。
在这里插入图片描述
也就是第一个rwx。

假设当前Linux系统上有用户itheima,还有其他用户yekai,且在yekai用户下有一个文件xxx.sh,当前用户为itheima,那么在当前用户下判断该文件的读写权限,执行结果将怎么样,又应该怎么看呢?
在当前用户下执行命令查看,
在这里插入图片描述
itheima对应该文件所属,属于其他用户,所以应该看第三个,为r-x.
我们再执行函数来判断下:
在这里插入图片描述
果然。

如果我们在前面加上sudo会怎么样呢?
在这里插入图片描述
使用sudo之后,当前用户变成root,对该文件来说,root用户拥有所有权限。

truncate

功能:截断文件。

使用man 2 truncate来查看函数说明。

#include <unistd.h>
#include <sys/types.h>

int truncate(const char *path, off_t length);

参数:
path:文件名,path对应的文件必须存在。
length:长度,长度如果大于源文件,直接拓展,如果小于源文件,截断为length长度。

返回值:
RETURN VALUE
On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

假设当前目录下有普通文件hello,文件内容为:
在这里插入图片描述
文件大小为:
在这里插入图片描述
执行代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    int size=0;
    scanf("%d",&size);
    truncate("hello",size);

    return 0;
}

执行代码,输入512之后。
在这里插入图片描述
打开文件看下文件内容。
	在这里插入图片描述
再执行代码,输入10之后。
在这里插入图片描述
打开文件看下。
在这里插入图片描述

原子操作

原子操作:不可分割的操作。
原子:不可分割的最小单位。
原子操作的作用:解决竞争和冲突。

在多线程和多进程并发中,解决竞争和冲突,最首要的操作就是将某些操作给原子化,比如互斥量加锁。

dup和dup2

#include <unistd.h>

int dup(int oldfd);
int dup2(int oldfd, int newfd);

dup和dup2的作用不同。

dup是复制参数所指定的文件描述符,然后返回一个当前可用的最小文件描述符。

dup2是重定向。
在这里插入图片描述
1、dup2会将后面参数(newfd)的指向重定向到前面参数(oldfd)的指向。
在这里插入图片描述
2、如果oldfd是一个可用的文件描述符,并且newfd与oldfd的值相同,那么dup2将什么都不做,并且返回newfd

3、dup2操作原子

close(1);
dup(fd);

dup2(fd,1);//在功能上等价与上面两句,但dup2比上面两句原子(不会因为时间片的结束而被中途切换出去)

dup和dup2的练习

在代码中执行2次
printf();
第一次输出到hello文件中,
后一次输出到屏幕上。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    //先备份现场
    int outfd =dup(1);

    int fd = open("hello",O_WRONLY|O_CREAT,0666);
    dup2(fd,1);
    printf("Hello.\n");
    close(fd);

    dup2(outfd,1);
    printf("Hello.\n");

    return 0;
}

运行程序:
在这里插入图片描述
再看下是否创建了hello这个文件
创建了,但是里面没有内容。
在这里插入图片描述
两次输出都输出到了屏幕终端。
那到底是什么原因呢?
是因为没有刷新。

下面结合多方面因素,完善这个程序,让其尽量符合多线程的Linux编程思想。


#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//现在探讨的这个程序考虑到的是当前实际、微观、宏观
int main()
{
    //先备份现场
    //返回当前可用的最小描述符,应该是3
    int outfd =dup(1);
    printf("outfd =%d.\n",outfd);//输出到终端上.

    int fd = open("hello",O_WRONLY|O_CREAT,0666);
    printf("fd =%d.\n",fd);//返回最小的文件描述符,应该是4

    //执行dup2函数后,
    //dup2函数的功能是先执行close(1),再将1重定向到fd所指向的文件。
    dup2(fd,1);//将标准输出重定向到打开的这个文件,
    printf("Hello.\n");
    fflush(stdout);//刷新缓冲区
    if(fd!=1)
    {
        //宏观上看:因为Linux是多线程并发,避免你把标准输出给关闭了,别人用不了了。
        close(fd);
//需要刷新,如果是以fopen()打开fclose()关闭,
//应该就不用刷新了吧,没有经过验证,只是这样想.
    }

    dup2(outfd,1);//将标准输出重新定向到终端上。
    printf("Hello.\n");

    return 0;
}

程序运行输出结果如下:
在这里插入图片描述

fcntl

管家级的函数,与文件相关的操作归它管,可以用它来实现上面提到的诸如dup、dup2等相关函数的功能。

NAME
       fcntl - manipulate file descriptor 操作文件描述符

SYNOPSIS
       #include <unistd.h>
       #include <fcntl.h>

       int fcntl(int fd, int cmd, ... /* arg */ );

DESCRIPTION
       fcntl() performs one of the operations described below on the open file descriptor fd.  The operation is determined by cmd.
       cmd是指你要对这个文件描述符做什么事情,之后的参数的含义是你要对这个文件描述符做的事情是否需要传参。

由于命令不同,会造成给该函数传参不同,同时返回值也不同。

命令和返回值,具体可参考man手册。

比如文件状态标志File status flags

The file status flags and their semantics(语义) are described in open(2).

F_GETFL (void)
Get the file access mode and the file status flags; arg is ignored.
获取文件访问模式和文件状态标志,此时不需要传参。

F_SETFD (int)
Set the file status flags to the value specified by arg.  File access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e., O_CREAT,O_EXCL,  O_NOCTTY,  O_TRUNC)  in arg are ignored.  On Linux this command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.  It is not possible to change the O_DSYNC and O_SYNC flags; see BUGS, below.   
将文件状态标志设置为arg指定的值。arg中的文件访问模式(O_RDONLY, O_WRONLY, O_RDWR)和文件创建标志(O_CREAT,O_EXCL, O_NOCTTY, O_TRUNC)被忽略。在Linux上,这个命令只能改变O_APPEND, O_ASYNC, O_DIRECT, O_NOATIMEO_NON - BLOCK标志。无法更改O_DSYNCO_SYNC标志;     

RETURN VALUE
For a successful call, the return value depends on the operation:
F_GETFD  Value of file descriptor flags.
F_GETFL  Value of file status flags.
使用演示如下:
#include <stdio.h>
#include <stdlib.h>

#define TTYA "/dev/tty11"
#define TTYB "/dev/tty12"

relay(int fd1,int fd2)
{
    int fd1_save,fd1_save;
    //将这两个文件描述符都做成以非阻塞方式打开
    fd1_save = fcntl(fd1,F_GETFL);
    fcntl(fd1,F_SETFL,fd1_save|O_NONBLOCK);

    fd2_save = fcntl(fd2,F_GETFL);
    fcntl(fd2,F_SETFL,fd2_save|O_NONBLOCK);
}

int main()
{
    int fd1,fd2;

    fd1 = open(TTYA,O_RDWR);
    if(fd1 < 0)
    {
        perror("open()");
        exit(1);
    }

    fd2 = open(TTY2,O_RDWR|O_NONBLOCK);
    if(fd2 < 0)
    {
        perror("open()");
        exit(1);
    }

    relay(fd1,fd2);

    close(fd1);
    close(fd2);
    return 0;
}

ioctl

管家级的函数,与设备相关的操作归它管。

/dev/fd目录

虚目录,显示的是当前进程的文件描述符信息。

如下图所示,现在是使用ls这个命令来看,所以显示的是ls这个命令实现所用到的文件描述符。
在这里插入图片描述
如何查看你正在运行的进程的文件描述符信息。
在程序的执行过程中打开/dev/fd/这个目录来查看。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuechanba

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值