• Linux 系统IO函数


    Linux系统IO函数

    1. int open(const char *pathname, int flags);
    2. int open(const char *pathname, int flags, mode_t mode);
    3. int close(int fd);
    4. ssize_t read(int fd, void *buf, size_t count);
    5. ssize_t write(int fd, const void *buf, size_t count);
    6. off_t lseek(int fd, off_t offset, int whence);
    7. int stat(const char *pathname, struct stat *statbuf);
    8. int lstat(const char *pathname, struct stat *statbuf);
    open

    在lesson9目录下,open.c使用函数1(上面列表的第一个),create.c使用函数2(上面列表的第二个)。

    在这里插入图片描述

    int open(const char *pathname, int flags, mode_t mode);//可变参数

    ​ 参数:

    flags:对文件操作权限的设置和其他设置。flags参数是一个int类型的数据,占4个字节,32位

    ​ flags 32个位 每一位都是一个标志位

    ​ - 必选项:O_RDONLY, O_WRONLY, or O_RDWR. 三个操作互斥

    ​ These request opening the file read-only, write-only,or read/write

    ​ - 可选项:O_CREAT 文件不存在,创建新文件

    mode:八进制的数,表示用户对新创建文件的操作权限,比如:0775

    ​ 最终的权限是:mode & ~umaskumask的作用是抹去某些权限

    ​ 返回值:

    ​ open(), openat(), and creat() return the new file descriptor,or -1 if an error occurred

    create.c中的代码如下:

    #include 
    #include 
    #include 
    #include
    #include
    
    int main(){
        //创建一个新的文件
        int fd= open("create.txt",O_RDWR | O_CREAT,0777);
        if(fd==-1){
            perror("open");
        }
        //关闭
        close(fd);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    需要注意的是函数2中的mode是一个八进制数,该数表示用户对新创建文件的操作权限,比如:0775,但最终的权限是由mode & ~umask决定的,umask的作用是抹去某些权限。在create.c的代码中,我们设置了mode是0777,但是对create.c编译运行之后产生的create.txt文件的操作权限如下:
    在这里插入图片描述
    操作权限为:rwx rwx r-x(111 111 101,即775),我们设置的mode为0777,但是实际文件的操作权限为0775,可见实际操作权限并不仅仅由我们设置的mode决定。

    read&write

    新建文件夹lesson10:
    在这里插入图片描述
    #include
    ssize_t read(int fd, void *buf, size_t count);

    • 参数:
      • fd:文件描述符,通过文件描述符操作某个文件
      • buf:记录内存中存放数据的地方,是个数组的地址
      • count:指定的数组的大小
    • 返回值
      • 成功:
        • 0:返回实际读取到的字节数
        • =0:文件读取完了
      • 失败:-1,并且设置errorno

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

    • 参数:

      • fd:文件描述符,通过文件描述符操作某个文件

      • buf:要往磁盘写入的数据

        • count:要写的数据的实际大小
    • 返回值

      • 成功:返回实际读取到的字节数
      • 失败:-1,并且设置errorno

    lesson10目录下有个大小为129772的英文txt文档,接下来使用read和write两个函数实现复制操作。
    copyfile.c:

    #include
    #include
    #include 
    #include 
    #include 
    int main(){
        //通过open打开english.txt文件
        /*
        查阅文档可知,需要导入三个头文件
            #include 
            #include 
            #include 
        */
       int srcfd=open("english.txt",O_RDONLY);
       if(srcfd==-1){
            perror("open");
            return -1;
       }
        //创建一个新文件
        int destfd=open("cpy.txt",O_WRONLY|O_CREAT,0664);
        if(destfd==-1){
            perror("open");
            return -1;
       }
        //频繁读写操作
        char buf[1024]={0};
        int len=read(srcfd,buf,sizeof(buf));
        //len>0表示文件中还有数据尚未被读取
        while((len=read(srcfd,buf,sizeof(buf)))>0){
            write(destfd,buf,len);
        }
        //关闭文件
        close(destfd);
        close(srcfd);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    编译链接c文件获得可执行文件copy,并运行copy:
    在这里插入图片描述

    LseeK
       #include 
       int fseek(FILE *stream, long offset, int whence);//标准c库的函数
    
    • 1
    • 2
       #include 
       #include 
    
       off_t lseek(int fd, off_t offset, int whence);//linux系统函数
    
        lseek()  repositions  the file offset of the open file description associated with the file descriptor fd to the argument offset according to the directive whence as follows:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 参数:

      • fd:文件描述符,通过文件描述符操作某个文件
      • offset:偏移量
      • whence:
        • SEEK_SET
          • 设置文件指针的偏移量
        • SEEK_CUR
          • 设置偏移量:当前位置+offset的值
        • SEEK_END
          • 设置偏移量:文件大小+offset的值
    • 返回值:返回文件指针的位置

    • 实例:

      • 移动文件指针到头文件:lseek(fd,0,SEEK_SET)
      • 获取当前文件指针的位置: lseek(fd,0,SEEK_CUR)
      • 获取文件长度:lseek(fd,0,SEEK_END)
      • 拓展文件长度:lseek(fd,100,SEEK_END)
        • 注意:需要写一次数据才能生效

      lesson11目录下有hello.txt和lseek.c两个文件,我们在lseek.c文件中对hello.txt的长度进行拓展。

    #include
    #include 
    #include 
    #include 
    #include
    
    int main(){
        int fd=open("hello.txt",O_RDWR);
        if(fd==-1){
            perror("open");
            return -1;
        }
        //拓展文件长度
        int ret= lseek(fd,100,SEEK_END);
        if(ret==-1){
            perror("lseek");
            return -1;
        }
        //写入一个空数据(最好写入一个空数据,不然不能拓展文件长度)
        write(fd," ",1);
        //关闭文件
        close(fd);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    编译链接lseek.c文件生成可执行文件并执行,可以看到hello.txt文件长度增加了101(使用NULL填充了100次,空格填充了一次)。
    在这里插入图片描述
    使用lseek拓展文件长度,可以用于下载任务。下载一个大小为2G的文件时,先使用lseek拓展出一个大小为2G的空间,再将下载的文件填充到该空间。

    stat&lstat

    创建目录lesson12

      #include 
       #include 
       #include 
    
       int stat(const char *pathname, struct stat *statbuf);
       int lstat(const char *pathname, struct stat *statbuf);//用来获取软链接文件的信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    参数:

    • pathname:操作文件的路径
    • statbuf:结构体变量,传出参数,用于保存获取到的文件信息
    • 返回值:On success, zero is returned. On error, -1 is returned, and errno is set appropriately.

    stat结构体:

    struct stat { 
    
        dev_t st_dev; // 文件的设备编号 
        ino_t st_ino; // 节点 mode_t st_mode; // 文件的类型和存取的权限 
        mode_t st_mode; // 文件的类型和存取的权限
        nlink_t st_nlink; // 连到该文件的硬连接数目 
        uid_t st_uid; // 用户ID 
        gid_t st_gid; // 组ID 
        dev_t st_rdev; // 设备文件的设备编号 
        off_t st_size; // 文件字节数(文件大小) 
        blksize_t st_blksize; // 块大小 
        blkcnt_t st_blocks; // 块数 
        time_t st_atime; // 最后一次访问时间 
        time_t st_mtime; // 最后一次修改时间 
        time_t st_ctime; // 最后一次改变时间(指属性)
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    image-20221109145054108

    S_IFMT八进制数值转为二进制为1111 0000 0000 0000 st_mode&S_IFMT判断文件类型

    在lesson12中编写stat.c代码查看文件a.txt的内容:

    #include 
    #include 
    #include 
    #include
    
    int main(){
        struct stat statbuf;
        int ret=stat("a.txt",&statbuf);
        if(ret==-1){
            perror("stat");
            return -1;
        }
    
        printf("size: %ld\n",statbuf.st_size);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    编译运行stat.c程序,运行结果如下:

    image-20221109150827094

    创建软连接文件b.txt 链接到a.txt文件

    通过ll和stat命令查看b.txt的实际大小是5字节

    在程序中stat查看b.txt获取的是a.txt的信息,lstat查看b.txt才获取到b.txt的信息

    image-20221109151642464

    模拟实现LS -L命令

    ls -l命令能获取目录下所有文件的权限 修改时间等信息。

    image-20221109152641327

    ls-l.c代码如下:

    #include 
    #include 
    #include 
    #include
    #include
    #include
    #include
    #include
    //模拟实现ls -l指令
    //-rw-rw-r-- 1 ccb ccb    12 11月  9 15:04 a.txt
    /*
        argc是参数数量,系统会根据传入的参数自动赋值
        一般输入有两个一个是可执行文件路径,一个是文件名称
    */
    int main(int argc,char * argv[]){
    
        //判断输入的参数是否正确并给出提示
        if(argc<2){
            printf("%s filename\n",argv[0]);
            return -1;
        }
        //通过stat函数查看用户指定文件的信息
        struct stat st;
        int res= stat(argv[1],&st);
        if(res==-1){
            perror("stat");
            return -1;
        }
    
        //获取文件权限和文件类型
        char parms[11]={0};//用于保存“-rw-rw-r-- ”字符串 
        switch (st.st_mode&S_IFMT)
        {
        case S_IFLNK:
            parms[0]='l';//软链接
            break;
        case S_IFDIR:
            parms[0]='d';//目录
            break;
        case S_IFREG:
            parms[0]='-';//普通文件
            break;
        case S_IFBLK:
            parms[0]='b';//块设备
            break;
        case S_IFSOCK:
            parms[0]='s';//套接字
            break;
        case S_IFCHR:
            parms[0]='c';//字符文件
            break;
        case S_IFIFO:
            parms[0]='i';//管道文件
            break;
        default:
            parms[0]='?';
            break;
        }
    
        //判断文件访问权限
        //文件所有者
        parms[1]=(st.st_mode&S_IRUSR)?'r':'-';
        parms[2]=(st.st_mode&S_IWUSR)?'w':'-';
        parms[3]=(st.st_mode&S_IXUSR)?'x':'-';
        //文件所在组
        parms[4]=(st.st_mode&S_IRGRP)?'r':'-';
        parms[5]=(st.st_mode&S_IWGRP)?'w':'-';
        parms[6]=(st.st_mode&S_IXGRP)?'x':'-';
        //其他人
        parms[7]=(st.st_mode&S_IROTH)?'r':'-';
        parms[8]=(st.st_mode&S_IWOTH)?'w':'-';
        parms[9]=(st.st_mode&S_IXOTH)?'x':'-';    
        //硬链接数
        int linkNum=st.st_nlink;
    
        //文件所有者
        char * fileUser=getpwuid(st.st_uid)->pw_name;
        //文件所在组
        char * fileGroup=getgrgid(st.st_gid)->gr_name;
        //文件大小
        long int fileSize=st.st_size;
        //获得修改时间
        char * editTime=ctime(&st.st_mtime);
        char mtime[512]={0};
        strncpy(mtime,editTime,strlen(editTime)-1);//去掉editTime最后的换行符
        char buf[1024];
        sprintf(buf,"%s %d %s %s %ld %s %s",parms,linkNum,fileUser,fileGroup,fileSize,mtime,argv[1]);
        printf("%s\n",buf);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    编译运行之后结果如下:

    image-20221109172501368

  • 相关阅读:
    结构光三维重建(一)条纹结构光三维重建
    云积天赫AI营销:重塑品牌营销新生态
    acrn guest 内存分析
    Zookeeper - 节点监听
    K8S群集调度
    告别互信息:跨模态人员重新识别的变分蒸馏
    Flink 命令行参数介绍
    硬盘压缩将C盘拓展成D盘和E盘
    蓝桥等考Python组别十四级005
    计算机网络第二章习题_物理层
  • 原文地址:https://blog.csdn.net/xiaodaitongxue/article/details/127737005