标准IO

目录

思维导图:

学习内容:

1. IO基础

2. 标准IO

2.1 标准IO提供的内容

2.2 FILE结构体

2.2.1 结构体解析

2.3 fopen 打开文件

2.4 fclose:关闭文件 

例如:

2.5 fgetc\fputc:单字符的输入输出 

 例如:

2.6 错误码 

 2.7 fputs\fgets:字符串输入输出

例如:

 2.8 缓冲区

课内练习:

1.使用fgetc完成,打开一个文件,统计该文件中的行数

2.使用fgetc和fputc完成,cp指令的功能,实现两个文件的拷贝,将src文件中的内容,拷贝到dest文件中 

课外作业:

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

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


思维导图:


学习内容:

1. IO基础

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

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

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

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

        5> 标准IO和文件IO的区别:

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

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

                3、标准IO有缓冲器,文件IO没有缓冲区

        6> 目前所接触过的IO函数:

                printf、scanf、putchar、getchar、puts、gets

        7> 常用的IO接口函数

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

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

2. 标准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.2 FILE结构体

        查看该结构体 :vi -t FILE

2.2.1 结构体解析

struct _IO_FILE {


   char* _IO_buf_base;   /* 缓冲区开始地址 */
   char* _IO_buf_end;    /* 缓冲区结束地址 */
   int _fileno;         //用于系统调用的文件描述符

 };   

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

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

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

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

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

2.3 fopen 打开文件

       #include <stdio.h>

       FILE *fopen(const char *pathname, const char *mode);
功能:打开给定路径的文件,以mode的形式打开
参数1: 要打开的文件的路径,是一个字符串
参数2:打开文件时的打开方式,是一个字符串
       r      以只读的形式打开一个文件,文件指针定位在开头
               Open text file for reading.  The stream is positioned at the beginning of the file.

       r+     以读写的形式打开一个文件,文件指针定位在开头
               Open for reading and writing.  The stream is positioned at the beginning of the file.

       w      以只写的形式打开文件,如果文件不存在则创建文件,如果文件存在则清空文件内容,文件指针定位在开头
               Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.

       w+      以读写的形式打开文件,如果文件不存在则创建文件,如果文件存在则清空文件内容,文件指针定位在开头
               Open for reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The stream is positioned
              at the beginning of the file.

       a      以追加的形式打开文件(结尾写),如果文件不存在则创建文件,如果存在则结尾写,文件指针定位在结尾
               Open  for appending (writing at end of file).  The file is created if it does not exist.  The stream is positioned at the end
              of the file.

       a+     以读或追加的形式打开文件,如果文件不存在,则创建文件,读指针定位在开头,写指针定位在结尾
               Open for reading and appending (writing at end of file).  The file is created if it does not exist.  The initial  file  posi‐
              tion for reading is at the beginning of the file, but output is always appended to the end of the file.
返回值:成功打开文件,返回该文件的地址,失败返回NULL,并置位错误码         

2.4 fclose:关闭文件 

       #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.5 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, 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> 错误码的相关函数 

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);
    功能:向标准出错缓冲区中,写入最新的错误码对应的信息
    参数:提示字符串,会自动提供一个冒号,并且输出结束后,会自动加一个换行
    返回值:无

 2.7 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, 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("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.使用fgetc完成,打开一个文件,统计该文件中的行数

解析:

#include<myhead.h>

int main(int argc, const char *argv[])
{
    //判断传入的参数是否为2个
    if(argc != 2)
    {
        printf("input file error!!!\n");
        printf("usage:./a.out fileName\n");
        return -1;
    }


    //表示传过来的有一个文件
    //定义文件指针
    FILE *fp = NULL;
    if((fp = fopen(argv[1], "r")) == NULL)
    {
        printf("fopen error\n");
        return -1;
    }

    //说明文件已经打开
    char buf = 0;        //接受字符
    int count = 0;       //统计行数
    while(1)
    {
        //从文件中读取一个字符
        buf = fgetc(fp);
        if(buf == EOF)
        {
            break;
        }

        //判断是否读取到回车
        if(buf == '\n')
        {
            count ++;
        }
    }

    //输出行号
    printf("该文件一共有%d行\n", count);

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

2.使用fgetc和fputc完成,cp指令的功能,实现两个文件的拷贝,将src文件中的内容,拷贝到dest文件中 

#include<myhead.h>

int main(int argc, const char *argv[])
{
    //判断传入的是否为三个文件
    if(argc != 3)
    {
        printf("input file error\n");
        printf("usage:./a.out srcfile destfile\n");
        return -1;
    }

    //以只读的形式打开源文件
    FILE *sfp = NULL;
    if((sfp = fopen(argv[1], "r")) == NULL)
    {
        printf("open src file error\n");
        return -1;
    }

    //以只写的形式打开目标文件
    FILE *dfp = NULL;
    if((dfp = fopen(argv[2], "w")) == NULL)
    {
        printf("open destfile error\n");
        return -1;
    }

    //定义搬运工
    char buf = 0;
    //循环从源文件中读取数据放入到目标文件中
    while(buf = fgetc(sfp) != EOF)
    {
        //将读取的数据写入目标文件中
        fputc(buf, dfp);
    }

    //关闭文件
    fclose(sfp);
    fclose(dfp);

    printf("拷贝成功\n");


    return 0;
}

课外作业:

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

解析:

#include<myhead.h>
int main(int argc, char const *argv[])
{
    FILE *fp = NULL;
    int count=0;
    char buf[50];
    if(argc != 2)
    {
        printf("intput file error\n");
        printf("usage: ./a.out xxx\n");
        return -1;
    }
    if((fp = fopen(argv[1],"r")) == NULL)
    {
        perror("fopen error");
        return -1;
    }
    while(fgets(buf,sizeof(buf),fp) != NULL)
    {
        count++;
    }
    fclose(fp);
    printf("有%d行\n",count);
    return 0;
}

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

解析:

#include<myhead.h>
int main(int argc, char const *argv[])
{
    FILE *fp1 = NULL;
    FILE *fp2 = NULL;
    if(argc != 3)
    {
        printf("intput file error\n");
        printf("usage: ./a.out xxx xxx\n");
        return -1;
    }
    if((fp1=fopen(argv[1],"r")) == NULL)
    {
        perror("fopen error");
        return -1;
    }
    if((fp2=fopen(argv[2],"w")) == NULL)
    {
        perror("fopen error");
        return -1;
    }
    char buf[50];
    while(fgets(buf,sizeof(buf),fp1) != NULL)
    {
        fputs(buf,fp2);
    }
    fclose(fp1);
    fclose(fp2);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值