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

news/2024/7/24 2:49:05 标签: linux, 运维, 服务器

一、系统调用

1、概述 

        系统调用: 就是操作系统内核 提供给用户可以操作内核 一组函数接口。用户 借助 系统调用 操作内核。比如用户可以通过文件系统相关的调用请求系统打开文件、关闭文件或读写文件,可以通过时钟相关的系统调用获得系统时间或设置定时器等。

        进程的空间分为:内核空间 和 用户空间。系统调用是属于操作系统内核的一部分,运行在内核态下,通过软件中断切换到内核态。

2、系统调用和库函数区别

系统调用 是内核提供的一组函数接口。

库函数 是第三方(用户提供)的函数接口。

        如果库函数没有调用系统调用该库函数不能操作内核。比如:字符串操作函数strcpy, bzero

        如果库函数 调用 系统调用该库函数能操作内核。比如:fopen fclose fwrite fget

3、系统调用及IO操作 

        系统调用是需要时间的,程序中频繁的使用系统调用会降低程序的运行效率。 文件IO中缓冲区刷新机制需要内核管理,库函数访问文件的时候根据需要,设置不同类型的缓冲区,从而减少了直接调用IO系统调用的次数,提高了访问效率。

二、文件描述符

1、概述 

        在 Linux的世界里一切设备皆文件,我们可以系统调用I/O 的函 数(I:input,输入;0:output..输出),对文件进行相应的操作 ( open()、close()、write()、read()等。

        打开现存文件或新建文件时,系统(内核)会返回一个文件描述符,文件描述符用来指定已打开的文件。这个文件描述符相当于这个已打开文件的标号,文件描述符是非负整数,是文件的标识,操作这个文件描述符相当于操作这个描述符所指定的文件。

        Linux将系统调用 打开或新建的文件 用非负整数 来表示。而这个非负整数 就是文件描述 符。

        系统会为每一个进程文件 分配一个文件描述符表管理该进程的所有文件描述符

        系统会为 每一个进程文件 打开三个文件描述符:0,1,2

  • 0:标准输入设备(键盘) scanf
  • 1:标准输出设备(终端)printf
  • 2:标准错误输出 (终端)perror

2、文件描述符表对文件描述符的管理

         文件描述符表 是通过 “位图” 来管理文件描述符。使用1024位(0-1023)二进制位管理,位数代表 的就是文件描述符,位上的值1表示打开,值0表示关闭,前三位(0-2)为标准文件描述符。打开文件的时候默认选择最小可用的文件描述符(3)给打开的文件用。

3、查看当前系统文件描述符最大数量ulimit -a

        查看命令:ulimit -a

修改命令:ulimit -n 2048 

 

三、文件IO的操作

        文件常用操作IO:open close read write

1、打开文件 open 

头文件: 

#include<sys/type.h>

#include<sys/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/O

mode文件在磁盘的用户权限:

        磁盘文件的用户权限分类:所有拥有者权限(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

 文件的最终权限=给定的权限异或掩码( & ~umask)

umask mode:设置掩码,mode为八进制数

umask -S:查看各组用户的默认操作权限

2、close 关闭文件描述符

        头文件:#include<unistd.h>

        函数:int close(int fd);

功能: 关闭已打开的文件

参数: fd : 文件描述符,open()的返回值

返回值: 成功:0 失败: -1并存放在全局变量errno中

        注意:close工作步骤,先将文件描述符的数量-1,当文件描述符的数量变为0的时候 ,系统回收文件描述符所占的内核空间。

 3、向文件写数据write

头文件:#include<unistd.h>

函数:size_t write(int fd, const void *buf, size_t count);

功能: 把指定数目的数据写到文件fd中

参数:

        fd : 文件描述符

        buf : 数据首地址

        count : 写入数据的长度(字节)

返回值: 成功:实际写入数据的字节个数 失败: - 1 

4、read读取文件数据

        #include<unistd.h>

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

功能: 把指定数目的数据读到内存(缓冲区)

参数:

        fd : 文件描述符

        buf : 内存首地址

        count : 读取的字节个数

返回值: 成功:实际读取到的字节个数,读完文件数据返回0         失败: - 1 

 5、综合案例:实现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)
    //若正确,argc=3,argv[0]=./a.out,argv[1]=a.txt,argy[2]=test
    if(argc!=3)
    {
        printf("缺少参数");
        return 0;
    }
    //以只读的方式 打开a.txt文件
    int fp_r=open(argv[1],O_RDONLY);
    if(fp_r<0)
    {
        perror("open");
        return 0;
    }
    //以写的方式 在test目录中打开a.txt
    char filename[32]="";
    sprintf(filename,"%s/%s",argv[2],argv[1]);
    int fp_w=read(filename,O_WRONLY|O_CREAT,0666);
    if(fp_w<0)
    {
        perror("open");
        return 0;
    }

    //不同的从fd_r中读取文件数据 写入fd_w文件中
    while(1)
    {
    unsigned char buf[128]="";
    int len=read(fp_r,buf,sizeof(buf));
    if(len<=0)
        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针对描述符提供控制。

头文件:

#include<unistd.h>

#include<fcntl.h>

函数:

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

参数:

fd:操作的文件描述符

cmd:操作方式

arg:针对cmd的值,fcntl能够接受第三个参数int arg。

返回值: 成功:返回某个其他值 失败:-1

fcntl函数有5种cmd功能:

  1.  复制一个现有的描述符(cmd=F_DUPFD)
  2. 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)
  3. 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL)
  4. 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)
  5. 获得/设置记录锁(cmd=F_GETLK, F_SETLK或F_SETLKW) 

设置一个存在的文件描述符的阻塞特性的步骤

  1. fcntl获取文件描述符的状态标记
  2. 修改 获取到的 文件描述符的状态标记
  3. 将修改后的状态标记 使用fcntl设置到文件描述符中 

五、获取文件的状态信息

头文件: 

#include<sys/type.h>

#include<sys/stat.h>

#include<unistd.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 失败: -1 

struct 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、打开目录(得到文件目录的句柄)

头文件:

#include<sys/types.h>

#include<dirent.h>

函数:

DIR *opendir(const char *name);

功能:打开一个目录

参数name:目录名

返回值: 成功:返回指向该目录结构体指针 失败:NULL

2、读取目录 

#include<dirent.h>

struct dirent *readdir(DIR *dirp);  

功能:读取目录 调用一次只能读取一个文件

参数 dirp:opendir的返回值

返回值: 成功:目录结构体指针 失败: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、关闭目录

头文件:

#include<sys/types.h>

#include<dirent.h>

函数:

int closedir(DIR *dirp);

功能:关闭目录

参数dirp:opendir返回的指针

返回值: 成功:0 失败:-1 


http://www.niftyadmin.cn/n/5408067.html

相关文章

Python中的自然语言处理和文本挖掘

在Python中&#xff0c;自然语言处理&#xff08;NLP&#xff09;和文本挖掘通常涉及对文本数据进行清洗、转换、分析和提取有用信息的过程。Python有许多库和工具可以帮助我们完成这些任务&#xff0c;其中最常用的包括nltk&#xff08;自然语言处理工具包&#xff09;、spaCy…

Shell编程——常见的脚本执行命令(七)

☺echo命令&#xff08;输出&#xff09; 用于字符串的输出&#xff0c;命令格式&#xff1a;echo string 显示普通字符&#xff1a;“”双引号可省略 显示转义字符&#xff1a;\斜杠放在转义符前面 显示变量&#xff1a; 显示换行&#xff08;\n&#xff09;&#xff1a;-e开…

JavaScript- 关于数据类型及其判断方法(超全)

JavaScript- 数据类型 分了2大类型&#xff1a;简单数据类型、复杂(引用)数据类型 涉及到数据类型的情况下&#xff0c;我们可以联想到typescript&#xff0c;ts是强类型语言&#xff0c;变量会进行类型检查&#xff0c;变量类型限制死&#xff0c;不能随便更改&#xff1b; 而…

基于springboot的学生评奖评优管理系统的设计与实现论文

基于springbootvue的学生评奖评优管理系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了学生评奖评优管理系统的开发全过程。通过分析学生评奖评优管理系统管理的不足&#xff0c;创建了一个计算机管理学生…

010-CSS-书写规范

书写规范 1、类名规范&#xff1a;清晰明了&#xff0c;尽量保持类名唯一性&#xff0c;使用两到三个完整单词&#xff0c;采用中划线拼接2、样式嵌套不要太深&#xff0c;以两到三层为最佳&#xff0c;否则影响查找性能3、抽离公共样式文件&#xff0c;抽离公共变量4、添加 sc…

CTF-NetA:一款专业的CTF网络流量分析工具

​ CTF-NetA&#xff1a;一款专业的CTF网络流量分析工具 介绍 CTF-NetA是一款专门针对CTF比赛的网络流量分析工具&#xff0c;可以对常见的网络流量进行分析提取flag&#xff0c;软件具有UI&#xff0c;不需要使用者具备任何基础能力。 该工具支持多种协议的分析&#xff0…

Vue+SpringBoot打造厦门旅游电子商务预订系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 景点类型模块2.2 景点档案模块2.3 酒店管理模块2.4 美食管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 学生表3.2.2 学生表3.2.3 学生表3.2.4 学生表 四、系统展示五、核心代码5.1 新增景点类型5.2 查询推荐的…

Golang Copy()方法学习

前言 主要是涉及到深浅拷贝相关的&#xff0c;但是在看的一个资料过程中发现他有错…并且一系列&#xff0c;复制粘贴他的&#xff0c;也都错了。 错误文章指路 很显然&#xff0c;Copy是深拷贝啊&#xff01;&#xff01;&#xff01; Copy功能 copy的代码很少&#xff0c…