一、简介

系统调用:#man 2 #就是系统调用函数操作系统实现并提供给外部应用程序的额编程接口(API,application programming interface)。是应用程序同系统之间数据交互的桥梁。
	
	linux中真正存在的函数并不和man 2中的系统函数名一致。
	我们能看到的系统调用(man 2中的)函数是linux内核函数的浅封装。如下图:

在这里插入图片描述

二、系统函数(调用)[文件IO相关]

我们接下来学习的函数严格上叫系统函数(系统调用浅封装),
只有这些函数可以驱动内核,
C语言的fputc等函数实际底层是这些系统函数的又封装。

注意:
	虽然系统函数直接调用内核,但因为缓冲区(详见下图和表)的存在当 单字节 用read、write时没有库函数fopen、fputc拷贝快。
	
	内核会有一个4096的缓冲区。用于预读入和缓输出。

使用问题:
	因为种种潜在的问题,例如上面的缓存问题,
	一般我们编程还是使用库函数,而不是直接使用系统函数。
	但具体的还是看场景需要。
区别系统函数库函数
缓存无用户级缓冲区有用户级缓冲区
写入内核方式直接与内核对接自身缓冲区满时才将数据推给内核

在这里插入图片描述

  1. open
作用:
	打开或创建文件。

man 2 open //get more information
//在vim命令模式下,光标至于按K直接进入man帮助中
1.function model
	#include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>

    int open(const char *pathname, int flags);  //默认权限打开
    int open(const char *pathname, int flags, mode_t mode); //指定权限,创建用

2.RETURN VALUE
	 open(), openat(), and creat() return the new file descriptor, 
	 or -1 if an error occurred (in which  case,  errno  is  set  appropri‐
       ately).

3.parameter information
	1)const char *pathname
		文件名及其路径。
		例: ''
	2)int flags
		O_RDONLY, O_WRONLY, or O_RDWR. // These request opening the file read-only, write-only, or read/write, respectively.
		O_APPEND //open append
		O_CREAT	//创建文件,需使用参数mode
		O_EXCL	//判断文件是否存在
		O_TRUNC	//截断文件大小为0,就是将文件清空
		O_NOBLOCK
		示例:
			O_RDONLY | O_CREAT | O_TRUNC //存在就只读打开并清空,否则创建 需mode参数
    3)mode_t mode //八进制的值
    	只在flag参数设置为O_CREAT时才需要使用。
	    4 2 1
	    R W X
	    示例:
	    	0666
	    	rw-rw-rw-
4.常见错误
	详见man 2 open

DEMO:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/open.c文件。
  1. close
作用:
	关闭文件描述符。

man 2 close
//在vim命令模式下,光标至于按K直接进入man帮助中

1.function model
	 #include <unistd.h>

     int close(int fd);

2.RETURN VALUE
       close() returns zero on success.  On error, -1 is returned, and errno is set appropriately.

3.parameter
	1)int fd
		already open descriptor ID。

DEMO:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/open.c文件。
  1. read
man 2 read
//在vim命令模式下,光标至于按K直接进入man帮助中

1.NAME:
       read - read from a file descriptor

2.SYNOPSIS
       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);

3.RETURN VALUE
	0:读到文件末尾
	成功:读到的字节数
	失败:-1,并设置errno
	-1:  errno = EAGIN 或 EWOULDBLOCK : read在以非阻塞方式读一个设备文件(或网络文件),但是没数据。需要再次读。
				 EINTR 				    被异常中断。需要重启。
				 ECONNRESET				连接被重置,需要close(fd),移出(除)监听队列。
		其他:error。
				 
				
		

DEMO:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/read.c文件。
  1. write
man 2 write
//在vim命令模式下,光标至于按K直接进入man帮助中

1.NAME
       write - write to a file descriptor

2.SYNOPSIS
       #include <unistd.h>

       ssize_t write(int fd, const void *buf, size_t count);

3.DESCRIPTION
       write() writes up to count bytes from the buffer starting at buf to the file referred to by the file descriptor fd.

4.RETURN VALUE
       On success, the number of bytes written is returned.  On error, -1 is returned, and errno is set to indicate the cause of the error.

DEMO:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/write.c文件。
  1. fcntl
man 2 fcntl
#
#直接修改已打开文件描述符的flags(O_RDONLY, O_WRONLY等)1.NAME
       fcntl - manipulate file descriptor

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

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

3.DESCRIPTION
       fcntl() performs one of the operations described below on the open file descriptor fd.  The operation is determined by cmd.

4.parameter
	F_GETFL:获取文件状态,//当设置此项时不需要再设置arg
	F_SETFL:设置文件状态//当设置此项时需要设置arg,arg为open的flags参数列表中的值
						//arg的设置涉及位图的概念,位图的每位都是二进制位,相应的每位对应一个flag,位图中标识1为生效,0为不生效。详见下图。
	//int flgs=fcntl(fd,F_GETFL);
	//flgs |= O_NONBLOCK;
	//fcntl(fd,F_SETFL,flgs);
DEMO:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/fcntl.c文件。

在这里插入图片描述

  1. lseek
man 2 lseek
1.NAME
       lseek - reposition read/write file offset

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

       off_t lseek(int fd, off_t offset, int whence);

3.parameter
	fd	//文件描述符
	offset	//偏移量
	whence	//起始偏移位置 SEEK_SET、SEEK_CUR、SEEK_END
4.RETURN VALUE
	error : -1
	success : 较起始位置偏移量
5.应用场景
	1)对同一文件描述符的“读”、“写”,使用的是同一偏移量.DEMO:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/lseek.c文件。
	2)使用lseek获取文件大小,DEMO:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/lseek_getfilesize.c文件。
	3)使用lseek拓展文件大小,要想让实际大小变为拓展后的大小必须要进行一次I\O操作。DEMO:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/lseek_expendfilesize.c文件。
	//拓展:函数truncate 直接拓展文件大小。 详情 man 2 truncate
  1. ioctl
    嵌入式相关,忽略。
  2. stat
man 2 stat //有example

1.NAME
	stat - get file status
2.SYNOPSIS
	int stat(const char *pathname, struct stat *statbuf);
3.parameter
	pathname:路径
	statbuf:结构体struct stat
		struct stat {
               dev_t     st_dev;         /* ID of device containing file */
               ino_t     st_ino;         /* Inode number */
               mode_t    st_mode;        /* File type and mode */
               nlink_t   st_nlink;       /* Number of hard links */
               uid_t     st_uid;         /* User ID of owner */
               gid_t     st_gid;         /* Group ID of owner */
               dev_t     st_rdev;        /* Device ID (if special file) */
               off_t     st_size;        /* Total size, in bytes */
               blksize_t st_blksize;     /* Block size 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
           };
4.RETURN VALUE
	On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.
5.应用
	1)获取文件大小
		statbuf.st_size
	2)获取文件类型
		st_mode使用宏函数判断文件类型,statbuf.st_mode。
		穿透符号链接:
			stat:会。lstat:不会
			例子:一个软连接,stat会直接获取软连接的原始文件,而lstat获取的是软连接自身。
	3)获取文件权限
		statbuf.st_mode.

文件由两字节构成,位图如下:
在这里插入图片描述

  1. access
man 2 access //用法看这个
1.NAME
       access, faccessat - check user's permissions for a file
       
2.SYNOPSIS
       #include <unistd.h>
       int access(const char *pathname, int mode);
  1. chmod
man 2 chmod //查看详情

1.NAME
       chmod, fchmod, fchmodat - change permissions of a file

2.SYNOPSIS
       #include <sys/stat.h>

       int chmod(const char *pathname, mode_t mode);
  1. truncate
man 2 truncate //

1.NAME
       truncate, ftruncate - truncate a file to a specified length

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

       int truncate(const char *path, off_t length);
  1. link
man 2 link //

1.NAME
       link, linkat - make a new name for a file
	   就是创建文件硬链接。
	   
2.SYNOPSIS
       #include <unistd.h>

       int link(const char *oldpath, const char *newpath);
  1. unlink
man 2 unlink 

1.NAME
       unlink, unlinkat - delete a name and possibly the file it refers to
	   就是删除硬链接,如果硬链接数为1,那就是删除文件.
	   
2.SYNOPSIS
       #include <unistd.h>

       int unlink(const char *pathname);
3.应用
	调用此函数后,只是让文件具备了被释放的条件,具体释放时机要等到所有打开该文件的进程关闭该文件,再由系统内部调度算法决定释放时间。
	也就是说unlink可以用来删除正在使用的文件。
  1. readlink
man 2 readlink
读取符号链接文件本身。
  1. rename
man 2 rename
重命名文件
  1. getcwd
man 2 getcwd
相当于 pwd
  1. chdir
man 2 chdir
相当于 cd
  1. opendir
man 3 opendir //库函数
打开目录文件
1.NAME
       opendir, fdopendir - open a directory

2.SYNOPSIS
       #include <sys/types.h>
       #include <dirent.h>

       DIR *opendir(const char *name);
3.RETURN VALUE
       The opendir() and fdopendir() functions return a pointer to the directory stream.  On error, NULL is returned, and errno is set appropriately.

  1. closedir
man 3 closedir //库函数
1.NAME
       closedir - close a directory

2.SYNOPSIS
       #include <sys/types.h>

       #include <dirent.h>

       int closedir(DIR *dirp);
3.RETURN VALUE
       The closedir() function returns 0 on success.  On error, -1 is returned, and errno is set appropriately.

  1. readdir
man 3 readdir //库函数

1.NAME
       readdir - read a directory
		每次读一个目录项。要全部读出来要循环。
2.SYNOPSIS
       #include <dirent.h>

       struct dirent *readdir(DIR *dirp);
3.parameter
struct dirent {
               ino_t          d_ino;       /* Inode number */
               off_t          d_off;       /* Not an offset; see below */
               unsigned short d_reclen;    /* Length of this record */
               unsigned char  d_type;      /* Type of file; not supported
                                              by all filesystem types */
               char           d_name[256]; /* Null-terminated filename */
           };
4.RETURN VALUE
       On success, readdir() returns a pointer to a dirent structure.
5.应用
	可以用来实现ls的功能。
	
	DEMO实现ls -R功能:链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/myls_R.c文件。
  1. 重定向
man 2 dup2

dup
dup2(fd1,fd2); //把给fd2的操作重定向给fd1上,
				//例如给fd2执行write(fd2,"1234",4);那么数据1234会写到fd1上		

fcntl也可以实现重定向。	

在这里插入图片描述

在这里插入图片描述

三、PCB进程模块和文件描述符

PCB进程控制块实际是一个结构体,
其中有一个成员为文件描述符指针,指向文件描述符表。
文件描述符表:
			键值对映射存放文件描述符,操作系统只暴露键,对值隐藏。
			键为整数(也就是我们写代码时获取的整数)。
			值对应一个指向文件结构体(struct file {})的指针。结构体中的信息就是一系列文件属性、IO缓冲区等信息。
			struct file {
				...
				文件偏移量,
				文件访问权限,
				文件打开标志,
				文件内核缓冲区的首地址;
				struct operations * f op;
				...
			};
文件描述符:
	内核默认有三个:
					标准输入	 0 	STDIN_FILENO
					标准输出	 1 	STDOUT_FILENO
					标准错误	 2	STDERR_FILENO.
	当我们使用系统函数新增时,总是从整数3开始。依次增加,最大为1024(最大值可修改).
	(新打开文件描述符遵循最小可用整数规则)

在这里插入图片描述

四、阻塞和非阻塞

阻塞和非阻塞是文件的特性(属性)。

产生阻塞场景:
	1)读设备文件(/dev/) 。 终端(Terminal)文件:/dev/tty .也就是终端的读写都是用的这个文件(默认是以阻塞状态打开的)。可以从新以非阻塞装填打开该文件进行输入输出。(详见下面Demo)
		 阻塞是一直持续等待输入,否则不输出。
		 非阻塞就是等两秒看有没有输入,有的话输入,没有的话歇会再看。
		 最优解:
		 		你有输入时就告诉我,然后我输出。(这样效率最高)
	2)读网络文件。
	(读常规文件无阻塞概念)
	
	DEMO:
		利用系统输入输出文件/dev/tty,去实现非阻塞输入输出,链接地址:git@github.com:Panor520/LinuxCode.git中LinuxCode/systemfunctions/tty.c文件。
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐