IO进程(标准IO)

标准IO

什么是标准IO

1.1 概念

标准IO: 是在C库中定义的一组专门用于输入输出的函数。

1.2 特点

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

例如:从硬盘中读1KB文件,每次只能读1B,循环读1024次。

  1. 围绕进行操作,流用FILE*来描述。

建立ctags索引: 密码1

注意: vi用ctags索引使用:

  1. vi -t 查找名称

输入前面序号,回车。

  1. 继续追踪:

将光标定位到要追踪的内容,ctrl+]

回退:ctrl+t

3)跳转到上次位置:ctrl+o

跳转到下次位置:ctrl+i

vscode:

跳转到定义:ctrl 左键

前后跳转:

ctrl alt -

ctrl shift -

  1. 标准IO默认打开三个流,stdin(标准输入)、stdout(标准输出)和stderr(标准错误)。

  1. 缓存区
  1. 全缓存:和文件相关

刷新全缓存:

  • 程序正常退出
  • 强制刷新:fflush(NULL);
  • 缓存区满
  1. 行缓存:和终端相关

刷新标准输出缓存的条件:

  • \n
  • 程序正常退出
  • 强制刷新:fflush(NULL);
  • 缓存区满

#include <stdio.h>

int main(int argc, char const *argv[])
{
    printf("hello wolrd");
    //printf("hello wolrd\n"); //\n不光是换行,还是刷新标准输出缓存区的条件(也就是把缓存区的内容打印到终端上)
    fflush(NULL);   //强制刷新缓存区
    while (1)
        ; //程序不会退出
    return 0;  //程序正常退出也可以刷新缓存区
}

  1. 不缓存:也就是没有缓存区,标准错误。

练习: 计算标准输出缓存区大小 KB

方法一:利用循环输出打印展示

方法二:利用结构体指针stdout

综上:当我们每次要在终端打印数据时,并不是将数据直接发送给标准输出设备,也就是并直接发送给显示器,而是将要打印的数据先存放到缓存区,当缓冲存数据满时,或者遇到\n,或者程序结束时,或者手动刷新缓存区时,缓冲区才会把数据传输到标准输出设备中,也就是显示器中进行输出。但是全缓存不能用\n刷新缓存

函数接口

2.1 打开文件fopen

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

返回值:
成功:文件流
失败:NULL,并且会设置错误码

补充:

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

2.2 关闭文件 fclose

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

int main(int argc, char const *argv[])
{
    FILE *fp;
    //1.打开文件
    //fp = fopen("test.txt", "r"); //如果不存在会错误,因为只读r模式
    fp = fopen("test.txt", "w");
    if (NULL == fp)
    {
        perror("fopen err");
        // while(1);  //标准错误不缓存,错误信息会打印
        return -1;
    }
    printf("fopen success\n");

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

2.3 文件读写操作

2.3.1 每次读写一个字符:fgetc()、fputc()

每次读一个字符fgetc()
int  fgetc(FILE * stream);
功能:从文件中读取一个字符,并将当前文件指针位置向后移动一个字符。
参数:stream:文件流
返回值:成功:读到的字符
       失败或读到文件末尾:EOF(-1)

每次写一个字符fputc()
int fputc(int c, FILE * stream);
功能:向文件中写入一个字符, 成功写入后文件指针会自动向后移动一个字节位置。
参数:c:要写的字符
   	  stream:文件流
返回值:成功:写的字符的ASCII
       失败:EOF(-1)

(1)针对文件读写
#include <stdio.h>

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

    char ch = fgetc(fp);
    printf("%d %c\n", ch, ch); //104 h

    ch = fgetc(fp);
    printf("%d %c\n", ch, ch); //101 e

    fputc('a', fp); //向文件中写个a
    fputc('b', fp); //向文件中写个b

    ch = fgetc(fp);
    printf("%d %c\n", ch, ch); //-1 EOF 因为以及到末尾了

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


(2)针对终端读写
#include <stdio.h>

int main(int argc, char const *argv[])
{
    char ch;
    ch = fgetc(stdin); //相当于getchar()
    printf("%d %c\n", ch, ch);

    fputc(ch, stdout); //相当于putchar()
    fputc(10, stdout);
    fputc('b', stdout);
    return 0;
}

补充:feof和ferror
int  feof(FILE * stream);
功能:判断文件有没有到结尾,也就是当前所在位置后面还有没有字符。
返回:如果到达文件末尾,返回非零值。如果后面还有字符则返回0。

例子:

int ferror(FILE * stream);
功能:检测文件有没有出错
返回:文件出错,返回非零值。如果没有出错,返回0

练习:cat 文件名
#include <stdio.h>
/* cat 文件名:查看文件内容,显示到终端。
   步骤:
        1.打开文件 fopen
        2.循环用fgetc获取文件内容
        3.当读到文件末尾标志EOF时结束
        4.将读取文件内容用fputc打印到终端
        5.关闭文件
*/
int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("err: %s <filename>\n", argv[0]); //提示一下正确的格式
        return -1;
    }

    //1.打开文件
    FILE *fp = fopen(argv[1], "r");
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }

    //2.循环用fgetc读文件,只要读到就fputc打印到终端
    char ch;
    while ((ch = fgetc(fp)) != EOF)
        fputc(ch, stdout);   //将读到字符打印到终端
  
    //3. 关闭文件
    fclose(fp);

    return 0;
}

2.3.2 每次一个字符串的读写fgets()和fpus()

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
  1. 针对终端读写
#include <stdio.h>

int main(int argc, char const *argv[])
{
    char buf[32] = "";
    //输入操作
    fgets(buf, 32, stdin); //输入hello\n,  此时buf中存入内容: hello\n\0
    printf("buf: %s\n", buf);

    fgets(buf, 32, stdin); //输入66\n,  此时buf中内容: 66\n\0o\n\0
    printf("buf: %s\n", buf);

    //输出操作
    fputs("world", stdout);
    fputs(buf, stdout);

    return 0;
}
  1. 针对文件读写
#include <stdio.h>
int main(int argc, char const *argv[])
{
    FILE *fp;
    char buf[32] = "";

    fp = fopen("test.txt", "r+");
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }
    printf("fopen success\n");
    //读写操作
    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: 66\0ld\n\0
    fputs(buf, stdout);

    fclose(fp);
    return 0;
}
练习:通过fgets实现"wc -l 文件名"命令功能(计算文件行数)
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    FILE *fp;
    char buf[32] = "";

    if (argc != 2)
    {
        printf("err: %s <filenme>\n",argv[0]);
        return -1;
    }

    fp = fopen(argv[1], "r");
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }

    //循环fgets读文件, 只要读到就判断是否有\n, 如果有就累加行数
    int len = 0;
    while (fgets(buf, 32, fp) != NULL)
    {
        if (buf[strlen(buf) - 1] == '\n')
            len++;
    }
    printf("%d %s\n", len, argv[1]);  //wc -l会少一行,因为最后一行没有换行

    fclose(fp);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值