7.26IO进程线程

笔记

IO

一.IO相关概念

        1>IO:(inout output)所谓IO,就是程序与外部设备进行信息交换的过程

        2>IO的分类:标准IO和文件IO

        3>标准IO:调用封装好的相关库函数,来实现数据的输入输出

        4>文件IO:调用系统(内核)提供的相关函数,来实现数据的输入输出

二.标准IO

2.1标准IO提供的内容

可以通过指令:man 7 stdio.h 可以查看该头文件提供的内容

1、标准的缓冲输入输出
2、提供的数据类型
       FILE          文件结构体类型.



       off_t         偏移量类型

       size_t        大小的类型,一般是一个long int类型
3、提供的偏移量的宏值
        SEEK_SET:文件起始位置
        SEEK_END:文件结束位置
        SEEK_CUR:文件当前位置
4、提供文件结束标志:EOF (end of file)
5、默认提供的文件指针:
        stdin:标准输入指针
        stdout:标准输出指针
        stderr:标准出错指针
6、标准IO会提供三种缓冲区:
        全缓存
        行缓存
     
2.2FILE结构体

1>如何追该结构体:可以使用vi-t FILE

2>结构体解析

245 struct _IO_FILE {


257   char* _IO_buf_base;   /* 缓冲区开始地址 */
258   char* _IO_buf_end;    /* 缓冲区结束地址 */


267 
268   int _fileno;         //用于系统调用的文件描述符

286 };    

3.当一个程序启动后,系统会自动打开三个文件指针:

        stdin:标准输入文件指针-->scanf、getchar、gets

        stdout:标准输出文件指针-->printf、putchar、puts

        stderr:标准出错文件指针-->perror

以以上三个文件指针,都是对于终端文件操作而言的

2.3fopen打开文件
       #include <stdio.h>

       FILE *fopen(const char *pathname, const char *mode);
    功能:以指定的方式打开一个给定的文件,并返回该文件的文件地址
    参数1:要打开的文件文件路径,可以是相对路径,也可以是绝对路径
    参数2:文件打开的方式,需要以以下字符开头的字符串
       r     以只读的形式打开文件,文件光标定位在开头.如果文件不存在,则报错

       r+     以读写的形式打开文件,文件光标定位在开头.如果文件不存在,则报错

       w      以只写的形式打开文件,如果文件存在,则清空文件内容,如果文件不存在,则创建该文件,文件光标定位在开头.

       w+     以读写的形式打开文件,如果文件存在,则清空文件内容,如果文件不存在,则创建该文件,文件光标定位在开头.

       a      以追加的形式打开文件,如果文件不存在则创建文件,文件光标定位在结尾

       a+     以读或者追加的形式打开文件,如果文件不存在,则创建文件,如果第一次是读数据,则光标定位在开头,否则定位在结尾
    返回值:成功调用返回打开的文件地址,失败返回NULL,并置位错误码
2.4fclose:关闭文件
       #include <stdio.h>

       int fclose(FILE *stream);
    功能:关闭给定的文件指针
    参数1:要关闭的文件指针
    返回值:成功返回0,失败返回EOF,并置位错误码



#include<myhead.h>

int main(int argc, const char *argv[])
{
    //定义文件类型的结构体以便于接受打开的文件地址
    FILE * fp = NULL;

    //打开一个文件
    //fp = fopen("./text.txt", "r");           //以只读的形式打开一个当前路径下的文件
    fp = fopen("./text.txt", "w");           //以只写的形式打开一个当前路径下的文件
    if(NULL == fp)
    {
        printf("fopen error\n");
        return -1;
    }
    printf("fopen success");   
    

    //关闭文件指针
    fclose(fp);


    return 0;
}
2.5fgetc\fputc:单字符的输入输出
       #include <stdio.h>

       int fputc(int c, FILE *stream);
    功能:将给定的字符,写入到文件指针stream指向的文件中去
    参数1:要写入的字符
    参数2:打开的文件指针
    返回值:成功返回写入字符的ascii值,失败返回EOF,并置位错误码
    
           #include <stdio.h>

       int fgetc(FILE *stream);
       功能:从指定文件中,读取一个字符
       参数:打开的文件指针
       返回值:从文件中读取的第一个字符的ascii值,失败返回EOF并置位错误码       
    


#include<myhead.h>

int main(int argc, const char *argv[])
{
    //定义文件类型的结构体以便于接受打开的文件地址
    FILE * fp = NULL;

    //打开一个文件
    //fp = fopen("./text.txt", "r");           //以只读的形式打开一个当前路径下的文件
    fp = fopen("./text.txt", "w+");           //以只写的形式打开一个当前路径下的文件
    if(NULL == fp)
    {
        printf("fopen error\n");
        return -1;
    }

    printf("fopen success\n");

    //向文件中写入字符
    fputc('H', fp);
    fputc('e', fp);
    fputc('l', fp);
    fputc('l', fp);
    fputc('o', fp);
    fputc('\n', fp);
    //文件中存储的结果为 Hello  
    //说明每次写入数据时,光标会自动后移
    

    //关闭文件指针
    fclose(fp);

    //再次以只读的形式打开文件
    fp = fopen("./text.txt", "r");           //以只写的形式打开一个当前路径下的文件
    if(NULL == fp)
    {
        printf("fopen error\n");
        return -1;
    }


    //定义变量用于读取数据
    char buf = 0;
    while(1)
    {
        buf = fgetc(fp);       //从fp中读取数据
        if(EOF == buf)          //表示文件读取结束
        {
            break;
        }

        printf("%c\t", buf);   //将读取的数据显示到终端
    }

    //关闭文件指针
    fclose(fp);


    



    return 0;
}
2.6有关错误代码问题

        1>错误码是调用内核提供的函数时,如果调用出错,那么内核空间会向用户空间反馈一个错误信息

        2>错误信息千奇百怪,并且是字符串内容,为了方便起见,给这些错误信息,进行编号

        3>如果,内核空间函数调用出问题时,只需要反馈错误编号即可,这个错误编号就叫做错误码

        4>常见错误码:可以通过指令vi-t-EIO查看

  5 #define EPERM        1  /* Operation not permitted */
  6 #define ENOENT       2  /* No such file or directory */
  7 #define ESRCH        3  /* No such process */
  8 #define EINTR        4  /* Interrupted system call */
  9 #define EIO      5  /* I/O error */
 10 #define ENXIO        6  /* No such device or address */
 11 #define E2BIG        7  /* Argument list too long */
 12 #define ENOEXEC      8  /* Exec format error */
 13 #define EBADF        9  /* Bad file number */
 14 #define ECHILD      10  /* No child processes */
 15 #define EAGAIN      11  /* Try again */
 16 #define ENOMEM      12  /* Out of memory */
 17 #define EACCES      13  /* Permission denied */
 18 #define EFAULT      14  /* Bad address */
 19 #define ENOTBLK     15  /* Block device required */
 20 #define EBUSY       16  /* Device or resource busy */
 21 #define EEXIST      17  /* File exists */
 22 #define EXDEV       18  /* Cross-device link */
 23 #define ENODEV      19  /* No such device */                                                            
 24 #define ENOTDIR     20  /* Not a directory */
 25 #define EISDIR      21  /* Is a directory */
 26 #define EINVAL      22  /* Invalid argument */
 27 #define ENFILE      23  /* File table overflow */
 28 #define EMFILE      24  /* Too many open files */
 29 #define ENOTTY      25  /* Not a typewriter */
 30 #define ETXTBSY     26  /* Text file busy */
 31 #define EFBIG       27  /* File too large */
 32 #define ENOSPC      28  /* No space left on device */
 33 #define ESPIPE      29  /* Illegal seek */
 34 #define EROFS       30  /* Read-only file system */
 35 #define EMLINK      31  /* Too many links */
 36 #define EPIPE       32  /* Broken pipe */
 37 #define EDOM        33  /* Math argument out of domain of func */
 38 #define ERANGE      34  /* Math result not representable */

        5>有关错误码的相关函数

    
、strerror函数
              #include <string.h>

       char *strerror(int errnum);
    功能:将给定的错误码,转变成错误信息
    参数1:错误码
    返回值:错误码对应的错误信息的字符串
    
    错误码如何获得?
    答:需要加一个头文件:#include<errno.h>
    #include <errno.h>

    const char * const sys_errlist[];
    int sys_nerr;
    int  errno;        /*  Not  really  declared  this  way;  see
 errno(3) */

2、perror函数
       #include <stdio.h>

       void perror(const char *s);
    功能:向标准出错缓冲区中,写入最新的错误码对应的信息
    参数:提示字符串,会自动提供一个冒号,并且输出结束后,会自动加一个换行
    返回值:无



#include<myhead.h>

int main(int argc, const char *argv[])
{
    //定义文件指针
    FILE *fp = NULL;
    if((fp = fopen("./file.txt", "r")) == NULL)
    {
        //strerror:将错误码转变成错误信息
        //printf("errno:%s\n", strerror(errno));
        perror("fopen error");

        return -1;
    }

    printf("open success\n");

    return 0;
}
2.7fputs\fgets:字符串输入输出
       #include <stdio.h>


       int fputs(const char *s, FILE *stream);
    功能:将给定的字符串,写入到文件中
    参数1:要写入的字符串起始地址
    参数2:打开的文件指针
    返回值:成功返回写入的字符个数(字符串长度),失败返回EOF
    
      #include <stdio.h>


       char *fgets(char *s, int size, FILE *stream);
       功能:从stream所指向的文件中,最多读取size-1的字符到s中,在读取过程中,如果遇到回车或者文件结束,会结束本次读取,并且会把回车也放入容器中。在后面自动加上'\0'
       参数1:存放数据的容器,一般是一个字符数组
       参数2:读取的大小
       参数3:文件指针
       返回值:成功返回容器的起始地址,失败返回NULL


fputs案例
#include<myhead.h>

int main(int argc, const char *argv[])
{
    //定义文件指针
    FILE *fp = NULL;
    if((fp = fopen("./file.txt", "w")) == NULL)
    {
        //strerror:将错误码转变成错误信息
        //printf("errno:%s\n", strerror(errno));
        perror("fopen error");

        return -1;
    }

    printf("open success\n");

    //向文件中写入字符串
    fputs("Hello world\n", fp);
    fputs("I love China\n", fp);
    fputs("Hua qing yuan jian\n", fp);
    fputs("good good study day day up\n", fp);


    //关闭文件
    fclose(fp);



    return 0;
}
fgets和fputs案例
#include<myhead.h>

int main(int argc, const char *argv[])
{
    //定义文件指针
    FILE *fp = NULL;
    if((fp = fopen("./file.txt", "w")) == NULL)
    {
        //strerror:将错误码转变成错误信息
        //printf("errno:%s\n", strerror(errno));
        perror("fopen error");

        return -1;
    }

    printf("open success\n");

    //向文件中写入字符串
    fputs("Hello world\n", fp);
    fputs("I love China\n", fp);
    fputs("Hua qing yuan jian\n", fp);
    fputs("good good study day day up\n", fp);

    //关闭文件
    fclose(fp);

    //以只读的形式重新打开文件
    if((fp = fopen("./file.txt", "r")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //循环读取数据
    char buf[128] = "";
    while(1)
    {
        //清空容器
        bzero(buf,  sizeof(buf));
        if( fgets(buf, sizeof(buf), fp)  == NULL)
        {
            break;    //说明文件读取结束
        }

        //输出读取的数据
        printf("%s", buf);   
    }

    printf("\n");

    //关闭文件
    fclose(fp);



    return 0;
}
2.8关于缓冲区

        1>标准IO提供了三种缓冲区:行缓存、全缓存、不缓存

        2>行缓存:有关标准输入、标准输出指针对应的缓存区,其大小位1024字节

        3>全缓存:有关普通文件指针对应的缓冲区,其大小位4096字节

        4>不缓存:有关标准出错文件指针对应的缓冲区,其大小位0

#include<myhead.h>

int main(int argc, const char *argv[])
{
    printf("行缓存的大小为:%ld\n", stdout->_IO_buf_end - stdout->_IO_buf_base);//0
    printf("行缓存的大小为:%ld\n", stdout->_IO_buf_end - stdout->_IO_buf_base);//1024
    getchar();        //使用一次标准输入
    printf("行缓存的大小为:%ld\n", stdin->_IO_buf_end - stdin->_IO_buf_base);//1024
    perror("usage");      //使用一次标准出错
    printf("不缓存的大小为:%ld\n", stderr->_IO_buf_end - stderr->_IO_buf_base);//0

    //验证全缓冲
    FILE *fp = NULL;
    if((fp = fopen("./tt.c", "w+")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    fgetc(fp);        //使用一次全缓冲
    printf("全缓存的大小为:%ld\n", fp->_IO_buf_end - fp->_IO_buf_base);//0
    


    //关闭
    fclose(fp);


    return 0;
}

        5>行缓存的刷新时机

1、换行会刷新行缓存
2、程序结束后,会自动刷新行缓存
3、当文件指针关闭后,会刷新行缓存
4、当使用fflush函数刷新文件指针时,会刷新行缓存
5、当输入输出切换时,会刷新行缓存
6、当缓存区满了后,再放数据时,会刷新行缓存

#include<myhead.h>

int main(int argc, const char *argv[])
{
    /*1、如果行缓存刷新时机未到,则不会刷新
    printf("hello world");            //不会输出
    while(1);
    */

    /*2、遇到换行,会刷新行缓冲
    printf("hello world\n");            //不会输出
    while(1);
    */

    /*3、当程序结束后,会刷新行缓冲
    printf("hello world");
    */

    /*4、当文件指针关闭后,会刷新行缓冲
    printf("hello world");
    fclose(stdout);            //关闭标准输出文件指针
    while(1);
    */

    /*5、手动调用fflush刷新缓冲器时,会刷新行缓冲
    printf("hello world");
    fflush(stdout);
    while(1);
    */


    /*6、当输入输出发生切换时,也会刷新行缓冲
    int num = 0;
    printf("请输入num的值:");
    scanf("%d", &num);
    */

    //7、当行缓冲区满了后,再往缓冲器区中放数据时,会刷新行缓冲
    
    for(int i=0; i<1999; i++)
    {
        printf("A");
    }
    while(1);


    return 0;
}

        6>全缓存的刷新时机

2、程序结束后,会自动刷新全缓存
3、当文件指针关闭后,会刷新全缓存
4、当使用fflush函数刷新文件指针时,会刷新全缓存
5、当输入输出切换时,会刷新全缓存
6、当缓存区满了后,再放数据时,会刷新全缓存


#include<myhead.h>

int main(int argc, const char *argv[])
{
    //定义文件指针
    FILE *fp = NULL;
    if((fp = fopen("./tt.c", "w+")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    /*1、换行不会刷新全缓冲
    fputs("hello a\n", fp);
    while(1);
    */

    /*2、程序结束后,会刷新全缓冲
    fputs("hello a\n", fp);
    */

    /*3、关闭文件指针时,会刷新全缓冲
    fputs("hello a\n", fp);
    fclose(fp);
    while(1);
    */
    
    /*4、使用fflush刷新文件指针时,会刷新全缓冲
    fputs("hello a\n", fp);
    fflush(fp);
    while(1);
    */

    /*5、输入输出发生切换时,会刷新全缓冲
    fputs("hello a\n", fp);
    fgetc(fp);
    while(1);
    */

    //6、当缓冲区满了后,会刷新全缓冲
    for(int i=0; i<4097; i++)
    {
        fputc('A', fp);
    }
    while(1);


    return 0;
}
2.9标准IO函数也可以使用stdin、stdout、stderr

        

#include<myhead.h>

int main(int argc, const char *argv[])
{
    char buf[20] = "";

    printf("请输入一个字符串:");
    fgets(buf, sizeof(buf), stdin);    //从终端读取数据到buf中
    buf[strlen(buf)-1] = '\0';   //将回车换成 '\0'
    printf("buf = %s", buf);


    fputs("我是一个错误", stderr);   //向标准出错中写入数据

    return 0;
}

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值