• Linux系统IO和标准IO的接口函数


    系统IO

    linux设计哲学
    everything is a file in linux
    也就是说在linux下面,操作任何东西都是在操作文件。或者说在Linux下面操作任何东西就是通过文件
    的接口去实现的。

    linux目前支持7种文件类型
    普通文件 (-)
    目录文件 (d)
    链接文件 (l)
    管道文件 (p)
    套接字文件 (s)
    块设备文件 (b)
    字符设备文件 (c)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    linux文件操作的原理

    文件
    文件属性 i-node 唯一标识文件存在与否
    文件内容

    文件操作过程:
    硬件
    i-node ->文件内容
    系统识别一个文件存在就会创建一个struct inode{}来管理文件的信息
    struct file用来描述打开一个文件
    操作文件的过程 struct file -》 struct inode —》硬件上的i-node—>文件的内容
    linux为了屏蔽文件操作的具体细节,他为每一个进程创建了一个文件表项来保存每个进程打开的文件。

    系统IO的接口函数

    1.open函数

    功能:用于打开或者创建一个文件
    头文件:
    #include 
    #include 
    #include 
    函数原型:
    int open(const char *pathname, int flags);
    int open(const char *pathname, int flags, mode_t mode);
    参数:
    @pathname:字符串类型 表示你要打开哪个文件,一般建议加上路径
    @flags:整数 打开的标志,表示以什么样的形式打开文件
    标志分为可选和必选:
    以下三个标志必选其一:
    O_RDONLY 只读打开文件
    O_WRONLY 只写打开文件
    O_RDWR. 可读可写
    除了以上的必选标志,还能以位或(|)的形式组合一些可选标志,
    O_CREAT 如果文件不存在,则创建它
    O_APPEND 把写入的数据追加到文件末尾
    O_NONBLOCK 以不阻塞的方式打开文件(默认是阻塞的)
    @mode:整数 表示权限,用于创建文件,指定文件的权限
    rwx --x r-x
    111 001 101 ==> 0715
    返回值:
    整数 失败返回-1,同时设置errno
    errno是一个全局(整数)变量,称为错误码,在头文件<errno.h>定义了该变量,害
    定义了一组与之相关的错误码常量。
    当系统函数调用失败的失败,会给errno设置一个大于0的值,
    系统提供了两个函数用来获取错误的原因:
    #include 
    void perror(const char *s);
    先输出字符串s,在输出一个:在输出一个空格 最后就是具体的错误信息。
    #include 
    char *strerror(int errnum);
    根据给定的errno的值,返回一个对应的错误码的信息
    成功返回一个新的文件描述符
    文件描述符什么?
    文件描述符是一个大于2整数,它实际上就是那个文件表项数组的下标
    当打开或者创建一个文件的时候,内核就会返回一个新的文件描述符。
    我们新打开一个文件,它的文件描述符一般是从3开始的
    当程序运行的时候,系统会自动打开三个文件,分别是:
    标准输入 0 一般指键盘
    标准输出 1 一般指屏幕
    标准错误 2 一般指屏幕
    
    • 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

    2.read函数

    功能:用于从打开的文件(描述符)中读取数据
    头文件:
    #include 
    函数原型:
    ssize_t read(int fd, void *buf, size_t count);
    参数:
    @fd:文件描述符 表示从哪个文件中读取数据
    @buf:数据缓存区 表示读到的数据放在哪里
    @count:你要读多少个(字节)
    返回值:
    失败返回-1,同时设置errno
    成功则返回实际读到的字节数
    如果返回0,表示到达文件末尾(读完了)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.write函数

    功能:用写入数据到打开的文件中(描述符)
    头文件:
    #include 
    函数原型:
    ssize_t write(int fd, const void *buf, size_t count);
    参数:
    @fd:文件描述符
    @buf:数据缓存区,表示我要把buf里面的内容写入到fd这个文件中
    @count:表示要写多少个(字节)
    返回值:
    失败返回-1,同时设置errno
    成功返回写入的字节数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.close函数

    功能:关闭一个文件
    头文件:
    #include 
    函数原型:
    int close(int fd);
    参数:
    @fd:文件描述符
    返回值:
    成功返回0
    失败返回-1,同时设置errno
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    5.lseek函数

    功能:重定位 读/写文件的偏移量(用于移动文本光标的位置)
    头文件:
    #include 
    #include 
    函数原型:
    off_t lseek(int fd, off_t offset, int whence);
    参数:
    @fd:文件描述符
    @offset:移动的偏移量 可正可负,正数表示往右边偏移,负数表示往左边偏移
    @whence:参照位置
    SEEK_SET 文件开头的位置
    SEEK_CUR 文件当前的位置
    SEEK_END 文件末尾的位置
    返回值:
    成功返回从文件开头到当前位置的偏移量
    失败返回-1,同时设置errno
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    例如
    求一个文件的大小

    int main(int argc, char const *argv[])
    {
    //以可读可写的形式打开./1.txt,如果没有则创建 并给权限0644
    int fd = open("./1.txt",O_RDWR | O_CREAT,0644);
    if(-1 == fd)//如果失败fd会变成-1,同时errno会被设置
    {
    //这两种二选1
    //perror("open 1.txt error");
    printf("open 1.txt error :%d %s\n", errno,strerror(errno));
    return 1;
    }
    //求文件大小
    int r = lseek(fd,0,SEEK_END);
    if(-1 == r)
    {
    perror("lseek error");
    return 1;
    }
    printf("该文件的大小为%d\n",r);
    return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    实现cp这个功能

    #include 
    #include 
    #include 
    #include 
    #include
    #include
    #include
    #include 
    #include 
    #include
    void mycp(char const * src_file, char const * dest_file)
    {
    //以只读的方式打开源文件
    int src_fd = open(src_file,O_RDONLY);
    if(-1 == src_fd)
    {
    perror("open src error");
    exit(1);//结束这个进程
    }
    //以只写的方式打开目标文件,如果没有则创建
    int dest_fd = open(dest_file,O_WRONLY | O_CREAT,0664);
    if(-1 == dest_fd)
    {
    perror("open dest error");
    exit(1);
    }
    char buf[1024] = {0};
    int r;
    while(1)
    {
    r = read(src_fd,buf,1024);
    if(-1 == r)
    {
    perror("read error");
    }
    if(0 == r)//读完了
    {
    break;
    }
    write(dest_fd,buf,r);//每次读到多少个字节就写多少个字节
    }
    //关闭目标文件和源文件
    close(src_fd);
    close(dest_fd);
    }
    int main(int argc, char const *argv[])//mycp ./1.txt /home/china/2.txt
    {
    //判断参数是否合法
    if(argc != 3)
    {
    printf("Usgae : %s  \n",argv[0]);
    return 1;
    }
    //拷贝文件
    mycp(argv[1],argv[2]);//argv[1] --> cp-->argv[2]
    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

    标准IO

    标准IO和系统IO
    系统IO的特点:
    通用,普通文件 管道文件 …套接字 都可以使用系统IO
    函数简单,不带缓冲

    标准IO的特点:
    跨平台,只要能跑c语言,标准IO就可以使用
    读写的方式更丰富
    一次性读写一个字节
    一次性读写一行字节

    读写效率更高
    使用标准IO,数据会先被存储,满足条件以后才能写入内核。

    标准IO的缓冲
    标准IO中提供三种缓冲:
    全缓冲:
    在这种情况下,需要把这个缓存区填满或者手动刷新或者关闭文件 才能进行实际的IO操作

    行缓冲:
    在这种情况下,当输入遇到换行时\n或者手动刷新或者关闭文件 才能进行实际的IO操作

    int main()
    {
    printf("abc\n");
    while(1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    无缓冲:
    在这种情况下,标准IO不缓存数据,直接进行IO操作

    int main()
    {
    perror("abc");
    while(1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    流与对象

    使用标准IO的方式与使用系统IO类似
    都是先打开一个文件建立从用户空间到内核空间的访问路径
    然后把打开操作的返回值,作为其他函数的参数。
    只不过系统IO,所有的IO操作都是围绕着文件描述符。
    在标准IO中,也有一个类似与文件描述符的概念,我们称之为流(stream),这个流实际上就是指向结构体FILE的指针
    结构体FILE其实就是对文件描述符,和读写缓存区的封装

    接口说明

    打开和关闭流

    功能:打开文件流
    头文件:
    #include 
    函数原型:
    FILE *fopen(const char *pathname, const char *mode);
    参数:
    @pathname: 你要打开文件的名字 建议路径
    @mode: 打开的模式
    r 以只读的方式打开文本文件,文本的光标位于文件开始的位置
    r+ 以读写的方式打开文件文件. 文本的光标位于文件开始的位置
    w 以写的方式打开这个文件,如果存在则清空,不存在则创建,文本的光标位于
    文件开始的位置
    w+ 以读写的方式打开文件. 如果存在则清空,不存在则创建,文本的光标位于
    文件开始的位置
    a 以追加写的方式打开文件(写数据到末尾)文件不存在则创建 ,文件的光标
    位于文件末尾
    a+ 以读和追加写的方式打开文件如果不存在则创建。
    如果是读则光标在文件开头,如果是写,则总是追加到文件末尾
    ┌─────────────┬───────────────────────────────┐
    │fopen() mode │ open() flags │
    ├─────────────┼───────────────────────────────┤
    │ r │ O_RDONLY │
    ├─────────────┼───────────────────────────────┤
    │ w │ O_WRONLY | O_CREAT | O_TRUNC │
    ├─────────────┼───────────────────────────────┤
    │ a │ O_WRONLY | O_CREAT | O_APPEND │
    ├─────────────┼───────────────────────────────┤
    │ r+ │ O_RDWR │
    ├─────────────┼───────────────────────────────┤
    │ w+ │ O_RDWR | O_CREAT | O_TRUNC │
    ├─────────────┼───────────────────────────────┤
    │ a+ │ O_RDWR | O_CREAT | O_APPEND │
    └─────────────┴───────────────────────────────┘
    O_TRUNC :如果文件存在,则清空
    返回值:
    成功FILE类型的指针,这个指针就是代表你要操作的哪个文件
    失败返回NULL,同时设置errno
    在程序启动的时候,同样有3个文件流被自动打开,
    分别是
    标准输入流 stdin 0
    标准输出流 stdout 1
    标准错误流 stderr 2
    功能:关闭文件流
    #include 
    int fclose(FILE *stream);
    返回值:
    成功返回0,失败返回-1,同时设置errno
    
    • 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

    读写文件块

    功能:用来从stream指定的文件读/写nmemb的对象,且每个对象大小为 size读/写到ptr
    头文件:
    #include 
    函数原型:
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    参数:
    @ptr 首地址,表示读出来的数据放到那里
    @size 每个对象的大小
    @nmemb 读到几个对象
    @stream:文件流 表示从哪个文件读
    返回值:
    成功返回实际读到的对象数
    失败返回-1,同时设置errno
    size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
    参数:
    @ptr 首地址 数据的来源
    @size 每个对象的大小
    @nmemb 写入几个对象 n*size
    @stream 文件流 表示写入哪个文件
    返回值
    成功返回实际写入的对象数
    失败返回-1,同时设置errno
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    读写一个字节

    #include 
    int fgetc(FILE *stream);//从指定的文件流中获取下一个字符,返回一个该字符的int形式
    int getc(FILE *stream);//与fgetc一样的功能,只不是getc是宏定义实现的(宏的效率会更高)
    int getchar(void); //---》等价fgetc(stdin) 从标准输入中获取一个字符
    #include 
    int fputc(int c, FILE *stream);//把指定字符c写入stream指定的文件中
    int putc(int c, FILE *stream);
    int putchar(int c); //把指定的字符写入到stdin ===》fputc(c,stdout);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    读写一行

    #include 
    char *gets(char *s);//从终端获取一个以换行符结束的字符串,保存在s指向的空间里面
    //从指定的文件流中,最多读取size-1个字符存放到s指向的空间
    //如果读到了\n也会保存在缓存区 不过有没有读到\n都会在最后吗补一个\0用来表示结束字符串
    char *fgets(char *s, int size, FILE *stream);
    int fputs(const char *s, FILE *stream);//把s指定的字符串写入到stream指定的文件
    流中
    int puts(const char *s);//等价于fputs(s,stdout); puts会自动换行
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    格式化IO

    #include 
    //按照格式输出数据 ---》stdout
    int printf(const char *format, ...);
    //按照格式输出数据 ---》stream指向的文件流中
    int fprintf(FILE *stream, const char *format, ...);
    //按照格式输出数据 ---》str指向地址
    int sprintf(char *str, const char *format, ...);
    多了一个大小的限制,
    int snprintf(char *str, size_t size, const char *format, ...);
    //从标准输入stdin 格式化输入数据
    int scanf(const char *format, ...);
    //从stream指定的文件流中输入格式化输入数据
    int fscanf(FILE *stream, const char *format, ...);
    //从s指定的文件流中输入格式化输入数据
    int sscanf(const char *str, const char *format, ...);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    定位流

    #include 
    //fseek功能和lseek类似,区别是
    //lseek的返回值是返回相对于文件开始的偏移量
    //fseek的返回值是0或者-1
    int fseek(FILE *stream, long offset, int whence);
    //用于返回文本光标的相对于文件开头的位置的偏移量大小
    long ftell(FILE *stream);
    //把文件的光标移回到文件开头的位置
    void rewind(FILE *stream);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    刷新流

    #include 
    int fflush(FILE *stream);
    使用fflush 刷新缓存区的数据,直接写入文件
    int main(int argc, char const *argv[])
    {
    printf("abc");
    fflush(stdout);
    while(1);
    return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    淘宝API详情接口调用示例
    docker技术学习
    Spring Cloud Alibaba —— 分布式事务组件
    Flink SQL TopN语句详解
    【LeetCode每日一题:799.香槟塔~~~模拟】
    2022.08.05_每日一题
    面试官:为什么说HTTPS比HTTP安全? HTTPS是如何保证安全的?
    SpringCloud (三) ——Nacos注册中心
    QSqlQuery查询语句
    【面试必刷TOP101】寻找峰值 & 数组中的逆序对
  • 原文地址:https://blog.csdn.net/weixin_46836491/article/details/126329362