IO进程中的标准IO

1.什么是标准IO

1.1概念

标准IO:在C库中定义的一组用于输入输出的函数接口

1.2特点

1.通过缓冲机制减少系统调用,提高效率

2.围绕流进行操作,用FILE*来表示

3.标准IO默认打开了三个流,分别是stdin(标准输入)、stdout(标准输出)、stderr(标准错误)

4.一般操作普通文件

2.缓存区

1.全缓存:和文件相关

刷新全缓存的方法:

  1. 正序正常退出(main中的return,exit函数)
  2. 缓存区溢出
  3. 强制刷新(fflush)
  4. fclose关闭对应的流

2.行缓存

刷新行缓存的方法:

  1. 正序正常退出(main中的return,exit函数)
  2. 缓存区溢出
  3. 强制刷新(fflush)
  4. fclose关闭对应的流
  5. \n

3.无缓存:没有缓冲区,标准错误

3.函数接口

3.1 打开文件fopen

man 3 fopen
FILE *fopen(const char *path, const char *mode);
功能:打开文件
参数:
    path:打开的文件路径
    mode:打开的方式
        r:只读,当文件不存在时报错,文件流定位到文件开头
        r+:可读可写,当文件不存在时报错,文件流定位到文件开头
        w:只写,文件不存在创建,存在则清空
        w+:可读可写,文件不存在创建,存在则清空
        a:追加(在末尾写),文件不存在创建,存在追加,文件流定位到文件末尾
        a+:读和追加,文件不存在创建,存在追加,读文件流定位到文件开头,写文件流定位到文件末尾
注:当a+的方式打开文件时,写只能在末尾进行追加,定位操作是无法改变写的位置,但是可以改变读的位置

返回值:
成功:文件流
失败:NULL,并且会设置错误码
void perror(const char *s);
功能:根据errno值打印对应的错误信息
参数:
	  s:提示语句
返回值:空

补充:perror()用来将上一个函数发生错误的原因输出到标准设备(stderr)。
参数s所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。
在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。
perror函数只是将你设置的一些信息和现在的errno所对应的错误一起输出。

3.2 关闭文件 fclose

int fclose(FILE* stream);
功能:关闭文件
参数:stream:文件流
#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    //打开文件
    //fp = fopen("a.c", "r");  //r: 只读,没有则报错
    fp = fopen("b.c", "r");
    if (NULL == fp)
    {
        perror("fopen err"); //如果设成r打开方式则没有这个文件会报错,因为只读方式打开
        return -1;
    }
    printf("fopen success\n");
    //关闭文件
    fclose(fp);  
    return 0;
}

3.3 文件读写操作:fgets、fputs、fread、fwrite

3.3.1 每次读写一串字符fgets()和fputs()

char * fgets(char *s,  int size,  FILE * stream);
功能:从文件中每次读取一行字符串
参数:    s:存放字符串的地址
         size:期望一次读取的字符个数
         stream:文件流
返回值:成功:s的地址
       失败或读到文件末尾:NULL
特性: 每次实际读取的字符个数为size-1个,会在末尾自动添加\0
       每次读一行,遇到\n或者到达文件末尾后不再继续读下一行
       并把它存储在s所指向的字符串内。

int  fputs(const char *s,  FILE * stream);
功能:向文件中写一个字符串
参数:s:要写的内容
     stream:文件流
返回值:成功:非负整数
       失败:EOF
针对终端
#include <stdio.h>

int main(int argc, char const *argv[])
{
    char buf[32] = "";
    //针对终端读写
    //输入操作
    fgets(buf, sizeof(buf), stdin); //终端输入的内容是hello\n
    printf("buf: %s\n", buf);   //此时buf里面存入的内容是: hello\n\0

    //输出操作
    fputs(buf, stdout);   //输出buf内容到终端: hello\n\0
    fputs("world",stdout);  //输出world\0到终端

    return 0;
}

注意: fgets一定会留一个位置给\0

针对文件

文件内容:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    //打开文件
    fp = fopen("test.txt", "r+");
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }

    //读写操作
    char buf[32] = "";
    fgets(buf, 32, fp); //buf:hello\n\0
    fputs(buf, stdout);

    fgets(buf, 32, fp); //buf:world\n\0
    fputs(buf, stdout);

    fgets(buf, 32, fp); //buf:6\0rld\n\0
    fputs(buf, stdout);

    //关闭文件
    fclose(fp);

    return 0;
}

3.3.2 二进制读写fread()和fwrite()

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从文件流读取多个元素(将二进制数据从文件读出)
参数:  ptr :是一个指针,是存放数据的存储空间的起始地址,用来存放读取元素
       size :元素大小  sizeof(元素数据类型)
       nmemb :读取元素的个数
       stream :要读取的文件流
返回值:成功:读取的元素的个数
       读到文件尾或失败: 0

size_t fwrite(const void *ptr, size_t size, size_t nmemb,
              FILE *stream);
功能:将二进制数据写入文件
参数: ptr :是一个指针,保存要输出数据的空间的地址。
     size :要写入的字节数 sizeof(数据类型)
     nmemb : 要进行写入元素的个数
      stream: 目标文件流指针
返回值:成功:写的元素个数
              失败 :-1
#include <stdio.h>
int main(int argc, char const *argv[])
{

    float arr[3] = {1.2, 2.3, 3.4};
    float data[3] = {0};
    //打开文件
    FILE *fp = fopen(argv[1], "r+");
    if (fp == NULL) //容错判断
    {
        perror("fopen err\n");
        return -1;
    }
    printf("fopen okk\n");

    fwrite(arr, 4, 3, fp);

    rewind(fp); //将流中的位置定位到开头, 不然上一步写操作位置到末尾了如果接着读的话什么也读不到

    fread(data, 4, 3, fp);

    for (int i = 0; i < 3; i++)
        printf("%f\n", data[i]);

    fclose(fp);
    return 0;
}

3.4 文件定位操作

void rewind(FILE *stream);
功能:将文件位置指针定位到起始位置

int fseek(FILE *stream, long offset, int whence);
功能:文件的定位操作
参数:stream:文件流
     offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移
     whence:相对位置:
           SEEK_SET:相对于文件开头
           SEEK_CUR:相对于文件当前位置
           SEEK_END:相对于文件末尾
返回值:成功:0
       失败:-1   
注:当打开文件的方式为a或a+时,fseek不起作用   
补充:其中SEEK_SET,SEEK_CURSEEK_END和依次为012.
例子:
把fp指针移动到离文件开头100字节处:fseek(fp,100,0);
把fp指针移动到离文件当前位置100字节处: fseek(fp,100,1);
把fp指针退回到离文件结尾100字节处: fseek(fp,-100,2);

long ftell(FILE *stream);
功能:获取当前的文件位置
参数:要检测的文件流
返回值:
成功:当前的文件位置,出错:-1
#include <stdio.h>
int main(int argc, char const *argv[])
{
    //打开文件
    FILE *fp = fopen("test.txt", "w+");
    if (fp == NULL) //容错判断
    {
        perror("fopen err\n");
        return -1;
    }
    printf("fopen okk\n");

    //相当于开头位置往后定位10个
    fseek(fp, 10, 0);
    fputs("a", fp);

    //相当于当前位置往后5个
    fseek(fp, 5, 1);
    fputs("hello", fp);

    //相当于最后位置往前1个
    fseek(fp, -1, 2);
    fputs("i", fp);

    long l = ftell(fp);
    printf("%ld\n", l);
    
    fclose(fp);
    return 0;
}

总结:为什么用标准IO?

  1. 因为读写文件通常是大量的数据(相对于底层驱动的系统调用所实现的数据操作单位),这时,使用库函数可以大大减少系统调用的次数。
  2. 为了保证可移植性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值