学习记录——day20 IO

IO基础

1、IO:(inout output)  程序与外部设备进行信息交换的过程

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

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

        2)文件IO:

3、文件IO和标准IO的区别:

        1)标准IO属于库函数,文件IO属于系统调用

        2)标准IO操作的是文件指针,文件IO操作的是文件描述符

4、阻塞IO和非阻塞IO

5、目前所接触过的IO函数:

        printf、scanf、putchar、getchar、puts、gets

6、常用的IO接口函数

        标准IO:fprint、fscanf、fputc、fgetc、fputs、fgets、fread、fwrite、fclose、fseek、ftell、                           rewind......

        文件IO:open、close、read、write、seek......

7、标准IO操作流程

标准IO

标准IO提供的内容

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

               1)标准的缓存输入输出

                2)提供的数据类型

                                FILE                文件结构体类型

                                off_t                偏移量类型

                                size_t              大小的类型

                3)提供了偏移量的宏值

                                SEEK_SEET:文件起始地址

                                SEEK_END:  文件结束位置

                                SEEK_CUR:   文件当前位置

                4)提供文件结束的标志:EOF(end of file)

                5)默认提供的文件指针

                                stdin:  标准输入指针

                                stdout:标准输出指针

                                stderr: 标准出错指针

                6)标准IO会提供三种缓冲区:

                                全缓冲

                                行缓冲

                                不缓冲

                                

FILE结构体

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

fopen 打开文件

       #include <stdio.h>

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

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

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

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

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

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

fclose 关闭

       #include <stdio.h>

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

fgetc、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, char const *argv[])
{
    FILE * fp = NULL;
    FILE * fq = 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);  //读取文件中的数据
        if (EOF == buf)
        {
            break;
        }
        printf("%c\t",buf);//将读取的数据显示到终端
    }
    
    //关闭文件
    fclose(fp);
    return 0;
}

使用fputc、fgetc完成cp功能

#include <myhead.h>
int main(int argc, char const *argv[])
{

    if (argc !=3)
    {
        printf("终端输入有误\n");
        return -1;
    }
    
    FILE * fp = NULL;
    FILE * fq = NULL;

    
    //拷贝
    //以只读的形式打开源文件
    if (NULL == (fp = fopen(argv[1],"r")))
    {
        printf("fopen error\n");
        return -1;
    }

    //以只写的形式打开目标文件
    if (NULL == (fq = fopen(argv[2],"w")))
    {
        printf("fopen error\n");
        return -1;
    }
    
    char temp = 0;
    while (1)
    {
        temp = fgetc(fp);  //读取文件中的数据
        if (EOF == temp)
        {
            break;
        }
        fputc(temp,fq);
    }
    printf("拷贝结束\n");
 

    //关闭文件
    fclose(fp);
    fclose(fq);
    return 0;
}

终端输入输出

拷贝结果

fputs、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
 

案例

#include <myhead.h>
int main(int argc, char const *argv[])
{
    FILE *fp = NULL;
    if (NULL == (fp = fopen("./02fputs.txt","w")))
    {
        perror("fopen error");
        return -1;
    }
    
    fputs("Hello world\n",fp);
    fputs("good good study\n",fp);
    fputs("day day up\n",fp);
    printf("fputs success\n");

    fclose(fp);

    if (NULL == (fp = fopen("./02fputs.txt","r")))
    {
        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);
    }
    putchar(10);

    fclose(fp);
    
    return 0;
}

 

有关错误码的问题

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

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

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

常见错误码:可通过 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 */

有关错误码的相关函数

1、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;
}

关于缓存区的问题

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

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

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

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

        

4、行缓存的刷新时机

        1)换行会刷新时机

        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;
}

5、全缓存的刷新时机

        1)换行不会刷新全缓存

        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;
}

标准IO函数也可以使用stdin、stdout、stderro

#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;
}

 作业

1、使用fgets统计给定文件的行号

#include <myhead.h>

int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("终端输入有误\n");
        return -1;
    }

    FILE *fp = NULL;

    if (NULL == (fp = fopen(argv[1], "r")))
    {
        perror("打开失败\n");
        return -1;
    }

    char buf[20] = "";
    int n = 0;
    while (1)
    {
        if ((fgets(buf, sizeof(buf), fp)) != NULL)
        {
            n++;
        }
        else
        {
            break;
        }
    }

    printf("该文件有%d行\n", n);

    fclose(fp);

    return 0;
}

测试文件:tt.txt

2、使用fgets、fputs完成两个文件的拷贝

#include <myhead.h>
int main(int argc, char const *argv[])
{
 
    if (argc !=3)
    {
        printf("终端输入有误\n");
        return -1;
    }
    
    FILE * fp = NULL;
    FILE * fq = NULL;
 
    
    //拷贝
    //以只读的形式打开源文件
    if (NULL == (fp = fopen(argv[1],"r")))
    {
        perror("fopen error");
        return -1;
    }
 
    //以只写的形式打开目标文件
    if (NULL == (fq = fopen(argv[2],"w")))
    {
        printf("fopen error\n");
        return -1;
    }
    
    char temp[20] = "";
    while (1)
    {
        bzero(temp,sizeof(temp));
        if ((fgets(temp,sizeof(temp),fp)) == NULL)
        {
            break;
        }
        fputs(temp,fq);
    }
    printf("拷贝结束\n");
 
 
    //关闭文件
    fclose(fp);
    fclose(fq);
    return 0;
}

拷贝结果

#include <myhead.h>
int main(int argc, char const *argv[])
{
 
    if (argc !=3)
    {
        printf("终端输入有误\n");
        return -1;
    }
    
    FILE * fp = NULL;
    FILE * fq = NULL;
 
    
    //拷贝
    //以只读的形式打开源文件
    if (NULL == (fp = fopen(argv[1],"r")))
    {
        perror("fopen error");
        return -1;
    }
 
    //以只写的形式打开目标文件
    if (NULL == (fq = fopen(argv[2],"w")))
    {
        printf("fopen error\n");
        return -1;
    }
    
    char temp[20] = "";
    while (1)
    {
        bzero(temp,sizeof(temp));
        if ((fgets(temp,sizeof(temp),fp)) == NULL)
        {
            break;
        }
        fputs(temp,fq);
    }
    printf("拷贝结束\n");
 
 
    //关闭文件
    fclose(fp);
    fclose(fq);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值