【linux】第二天 linux系统调用及文件IO操作

发布时间:2026/7/24 20:19:07
【linux】第二天 linux系统调用及文件IO操作 目录一、系统调用1、概述2、系统调用和库函数区别3、系统调用及IO操作二、文件描述符1、概述2、文件描述符表对文件描述符的管理3、查看当前系统文件描述符最大数量ulimit -a三、文件IO的操作1、打开文件 open2、close 关闭文件描述符3、向文件写数据write4、read读取文件数据5、综合案例实现cp(copy)命令四、文件的阻塞特性1、open打开文件 默认为阻塞特性2、 open打开文件 设置为非阻塞特性3、通过fcntl设置文件的阻塞特性五、获取文件的状态信息六、文件目录操作1、打开目录(得到文件目录的句柄2、读取目录3、关闭目录一、系统调用1、概述系统调用 就是操作系统内核 提供给用户可以操作内核 一组函数接口。用户 借助 系统调用 操作内核。比如用户可以通过文件系统相关的调用请求系统打开文件、关闭文件或读写文件可以通过时钟相关的系统调用获得系统时间或设置定时器等。进程的空间分为内核空间 和 用户空间。系统调用是属于操作系统内核的一部分运行在内核态下通过软件中断切换到内核态。2、系统调用和库函数区别系统调用 是内核提供的一组函数接口。库函数 是第三方用户提供的函数接口。如果库函数没有调用系统调用该库函数不能操作内核。比如字符串操作函数strcpy bzero如果库函数调用系统调用该库函数能操作内核。比如fopen fclose fwrite fget3、系统调用及IO操作系统调用是需要时间的程序中频繁的使用系统调用会降低程序的运行效率。 文件IO中缓冲区刷新机制需要内核管理库函数访问文件的时候根据需要设置不同类型的缓冲区从而减少了直接调用IO系统调用的次数提高了访问效率。二、文件描述符1、概述在 Linux的世界里一切设备皆文件我们可以系统调用I/O 的函 数Iinput,输入;0output..输出对文件进行相应的操作 ( open()、close()、write()、read()等。打开现存文件或新建文件时系统内核会返回一个文件描述符文件描述符用来指定已打开的文件。这个文件描述符相当于这个已打开文件的标号文件描述符是非负整数是文件的标识操作这个文件描述符相当于操作这个描述符所指定的文件。Linux将系统调用 打开或新建的文件 用非负整数来表示。而这个非负整数 就是文件描述 符。系统会为每一个进程文件 分配一个文件描述符表管理该进程的所有文件描述符。系统会为 每一个进程文件 打开三个文件描述符0,1,20标准输入设备键盘 scanf1标准输出设备终端printf2标准错误输出终端perror2、文件描述符表对文件描述符的管理文件描述符表 是通过 “位图” 来管理文件描述符。使用1024位0-1023二进制位管理位数代表 的就是文件描述符位上的值1表示打开值0表示关闭前三位0-2为标准文件描述符。打开文件的时候默认选择最小可用的文件描述符3给打开的文件用。3、查看当前系统文件描述符最大数量ulimit -a查看命令ulimit -a修改命令ulimit -n 2048三、文件IO的操作文件常用操作IO:open close read write1、打开文件 open头文件#includesys/type.h#includesys/stat.h#include funtl.h相关函数函数功能 打开文件如果文件不存在则可以选择创建。//二参数open用于 打开已存在的文件int open(const char *pathname, int flags);//三参数open用于 打开不存在的文件 mode是文件在磁盘上的权限int open(const char *pathname, int flags, mode_t mode);//返回值成功返回最小文件描述符失败返回-1参数pathname文件的路径及文件名flags打开文件的行为标志必选项O_RDONLY以只读方式打开,O_WRONLY以只写方式打开,O_RDWR以可读可写方式打开mode这个参数只有在文件不存在时有效指新建文件时指定文件的磁盘权限flags 文件的操作权限可选项和必选项按位或起来取值含义O_CREAT文件不存在则创建文件文件存在则先删除再重新创建文件使用此选项时需使用mode说明文件的权限O_EXCL如果同时指定了O_CREAT且文件已经存在则出错防止已有文件被删除O_TRUNC如果文件存在则清空文件内容O_APPEND写文件时数据添加到文件末尾O_NONBLOCK对于设备文件, 以O_NONBLOCK方式打开可以做非阻塞I/Omode文件在磁盘的用户权限磁盘文件的用户权限分类所有拥有者权限u、同组用户权限(g)、其他用户权限(o)权限分为读4、写2、执行1可以相互组合7---可读可写可执行 6---可读可写 5---可读可执行4---只读 3---可写可执行 2---只写 1---可执行mode的权限表示0xxx 每一个x都是4、2、1的组合如前第一个0代表其为八进制数0777 所有者、同组用户、其他用户都是可读可写可执行0666 所有者、同组用户、其他用户都是可读可写查看mode的系统权限掩码umask查看掩码命令umask文件的最终权限给定的权限异或掩码 ~umaskumask mode设置掩码mode为八进制数umask -S查看各组用户的默认操作权限2、close 关闭文件描述符头文件#includeunistd.h函数int close(int fd);功能 关闭已打开的文件参数 fd : 文件描述符open()的返回值返回值 成功0 失败 -1并存放在全局变量errno中注意close工作步骤先将文件描述符的数量-1当文件描述符的数量变为0的时候 系统回收文件描述符所占的内核空间。3、向文件写数据write头文件#includeunistd.h函数size_t write(int fd, const void *buf, size_t count);功能 把指定数目的数据写到文件fd中参数fd : 文件描述符buf : 数据首地址count : 写入数据的长度字节返回值 成功实际写入数据的字节个数 失败 - 14、read读取文件数据#includeunistd.hsize_t read(int fd, void *buf, size_t count);功能 把指定数目的数据读到内存缓冲区参数fd : 文件描述符buf : 内存首地址count : 读取的字节个数返回值 成功实际读取到的字节个数读完文件数据返回0 失败 - 15、综合案例实现cp(copy)命令举例cp b.txt test 将b.txt文件拷贝到test目录中#include stdio.h #include string.h #include unistd.h #include sys/types.h #include sys/stat.h #include sys/fcntl.h int main(int argc,char *argv[])//argc为传参个数指针数组argv存放每个参数的内容 { //判断参数是否正确./a.out a.txt test //若正确argc3argv[0]./a.out,argv[1]a.txt,argy[2]test if(argc!3) { printf(缺少参数); return 0; } //以只读的方式 打开a.txt文件 int fp_ropen(argv[1],O_RDONLY); if(fp_r0) { perror(open); return 0; } //以写的方式 在test目录中打开a.txt char filename[32]; sprintf(filename,%s/%s,argv[2],argv[1]); int fp_wread(filename,O_WRONLY|O_CREAT,0666); if(fp_w0) { perror(open); return 0; } //不同的从fd_r中读取文件数据 写入fd_w文件中 while(1) { unsigned char buf[128]; int lenread(fp_r,buf,sizeof(buf)); if(len0) break; printf(读取的数据大小为%d,len); write(fp_w,buf,sizeof(buf)); } //关闭文件 close(fp_r); close(fp_w); return 0; }四、文件的阻塞特性对于一些设备文件读写操作,如管道,套接字,标准设备文件,默认缓冲区没有数据读会带阻塞,默认缓存区满的状态,写也会阻塞。文件描述符决定阻塞和非阻塞而不是read write函数。文件描述符默认为阻塞的。1、open打开文件 默认为阻塞特性文件描述符 事先不存在用open。如果从终端输入的数据没有换行符默认调用read读终端设备就会阻塞。2、 open打开文件 设置为非阻塞特性3、通过fcntl设置文件的阻塞特性文件描述符事先存在用funtl。 功能改变已打开的文件性质fcntl针对描述符提供控制。头文件#includeunistd.h#includefcntl.h函数int fcntl(int fd, int cmd, ... /* arg */ );参数fd操作的文件描述符cmd操作方式arg针对cmd的值fcntl能够接受第三个参数int arg。返回值 成功返回某个其他值 失败-1fcntl函数有5种cmd功能复制一个现有的描述符cmdF_DUPFD获得设置文件描述符标记(cmdF_GETFD或F_SETFD)获得设置文件状态标记(cmdF_GETFL或F_SETFL)获得设置异步I/O所有权(cmdF_GETOWN或F_SETOWN)获得设置记录锁(cmdF_GETLK, F_SETLK或F_SETLKW)设置一个存在的文件描述符的阻塞特性的步骤fcntl获取文件描述符的状态标记修改获取到的 文件描述符的状态标记将修改后的状态标记 使用fcntl设置到文件描述符中五、获取文件的状态信息头文件#includesys/type.h#includesys/stat.h#includeunistd.h函数int stat(const char *path, struct stat *buf);int lstat(const char *pathname, struct stat *buf);功能 获取文件状态信息stat和lstat的区别 当文件是一个符号链接时lstat返回的是该符号链接本身的信息 而stat返回的是该链接指向的文件的信息。参数path/pathname文件名buf保存文件信息的结构体返回值 成功 0 失败: -1struct stat结构体说明struct stat { dev_t st_dev; //文件的设备编号 ino_t st_ino; //节点 mode_t st_mode; //文件的类型和存取的权限 nlink_t st_nlink; //连到该文件的硬连接数目刚建立的文件值为1 uid_t st_uid; //用户ID gid_t st_gid; //组ID dev_t st_rdev; //(设备类型)若此文件为设备文件则为其设 备编号 off_t st_size; //文件字节数(文件大小) blksize_t st_blksize; //块大小(文件系统的I/O 缓冲区大小) blkcnt_t st_blocks; //块数 time_t st_atime; //最后一次访问时间 time_t st_mtime; //最后一次修改时间 time_t st_ctime; //最后一次改变时间(指属性) };st_mode(16位整数)参数说明 :由于上述形式的测试是普通的因此POSIX定义了其他宏以便更简洁地编写st_mode中的文件类型测试S_ISREG(st_mode)是否是普通文件(regular file)S_ISDIR(st_mode)是否是目录文件(directory)S_ISCHR(st_mode)是否是字符设备(character device)S_ISBLK(st_mode)块设备(block device)S_ISFIFO(st_mode)管道S_ISLNK(st_mode)符号链接(软连接st_mode控件的文件模式组件定义了下列掩码值:六、文件目录操作读取一个目录下的所有文件名1、打开目录(得到文件目录的句柄头文件#includesys/types.h#includedirent.h函数DIR *opendir(const char *name);功能打开一个目录参数name目录名返回值 成功返回指向该目录结构体指针 失败NULL2、读取目录#includedirent.hstruct dirent *readdir(DIR *dirp);功能读取目录 调用一次只能读取一个文件参数 dirpopendir的返回值返回值 成功目录结构体指针 失败NULL结构体dirent说明struct dirent { ino_t d_ino; // 此目录进入点的inode off_t d_off; // 目录文件开头至此目录进入点的位移 signed short int d_reclen; // d_name 的内容长度, 不包含NULL 字符 unsigned char d_type; // d_type 所指的文件类型 char d_name[256]; // 文件名 };d_type相关数据3、关闭目录头文件#includesys/types.h#includedirent.h函数int closedir(DIR *dirp);功能关闭目录参数dirpopendir返回的指针返回值 成功0 失败-1