day19

一、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和非阻塞IO
7>    目前所接触过的IO函数:
printf、scanf、putchar、getchar、puts、gets
8>    常用的IO接口函数
标准IO:fprint、fscanf、fputc、fgetc、fputs、fgets、fread、 fwrite、fopen、fclose、fseek、ftell、rewind。。。
文件IO:open、close、read、write、seek。。。
9>    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.2    FILE结构体


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

struct _IO_FILE

{
char* _IO_buf_base;   /* 缓冲区开始地址 */
char* _IO_buf_end;    /* 缓冲区结束地址 */
int _fileno;         //用于系统调用的文件描述符
 };    
3>    当一个程序启动后,系统会自动打开三个文件指针:
stdin:标准输入文件指针    --->    scanf、getchar、gets
stdout:标准输出文件指针    ----> printf、putchar、puts
stderr:标准出错文件指针    --->    perror
以上三个文件指针,都是针对于终端文件操作而言的


2.3    fopen 打开文件

       #include <stdio.h>
       FILE *fopen(const char *pathname, const char *mode);
    功能:以指定的方式打开一个给定的文件,并返回该文件的文件地址
    参数1:要打开的文件文件路径,可以是相对路径,也可以是绝对路径
    参数2:文件打开的方式,需要以以下字符开头的字符串
       r     以只读的形式打开文件,文件光标定位在开头.如果文件不存在,则报错
       r+     以读写的形式打开文件,文件光标定位在开头.如果文件不存在,则报错
       w      以只写的形式打开文件,如果文件存在,则清空文件内容,如果文件不存在,则创建该文件,文件光标定位在开头.
       w+     以读写的形式打开文件,如果文件存在,则清空文件内容,如果文件不存在,则创建该文件,文件光标定位在开头.
       a      以追加的形式打开文件,如果文件不存在则创建文件,文件光标定位在结尾
       a+     以读或者追加的形式打开文件,如果文件不存在,则创建文件,如果第一次是读数据,则光标定位在开头,否则定位在结尾
    返回值:成功调用返回打开的文件地址,失败返回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;
}
 

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(1)
    {
        buf = fgetc(sfp);        //从源文件中读取
        if(buf == EOF)
        {
            break;
        }
 
        //将读取的数据写入目标文件中
        fputc(buf, dfp);
    }
 
    //关闭文件
    fclose(sfp);
    fclose(dfp);
 
    printf("拷贝成功\n");
 
 
    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);
    功能:向标准出错缓冲区中,写入最新的错误码对应的信息
    参数:提示字符串,会自动提供一个冒号,并且输出结束后,会自动加一个换行
    返回值:无
    
 

#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.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
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;
}
使用fgets统计给定文件的行号

#include <myhead.h>
int main(int argc, const char *argv[])
{   //判断是否有两个输 入
    if (argc != 2)
    {
        printf("input file error!!!\n");
        printf("usage:./a.out fileName\n");
        return -1;
    }
    /*表示传过来的有一个文件开始定义文件指针*/
    FILE *er = NULL;
    if ((er = fopen(argv[1], "r")) == NULL)
    {
        printf("fopen error\n");
    }
    char a[128] = " ";//接受字符串
    int count = 1;//行数
    while (1)
    {
        if (fgets(a, sizeof(a), er)==0)//如果成功接受字符数为0
        {
            break;//退出循环
        }
        else
        {
            count++;//计数+1
        }
    }
     printf("%d\n", count);//打印行数
    fclose(er);//关闭文件
    return 0;
}


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

#include <myhead.h>
int main(int argc, const char *argv[])
{
	if (argc != 3)//判断输入是否有三个
	{
		printf("error");
	}
	FILE *A = NULL;//定义文件指针
	FILE *B = NULL;
	if ((A = fopen(argv[1], "w")) == NULL)
	{
		printf("fopen error\n");
	}
	if ((B = fopen(argv[2], "r")) == NULL)
	{
		printf("fopen error\n");
	}
	while (1)
	{
		char s[128] =" ";//定义接受字符串
		if (fgets(s, sizeof(s), B) == 0)//成功接受字符数为0
		{
			break;
		}
        fputs(s,A);//向指针A指向的文件写入接受的字符串
	}
	    fclose(A);//关闭文件
		fclose(B);
		return 0;
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值