标准IO的概念及常用函数


前言

标准输入/输出(Standard Input/Output)是编程中非常基础且重要的概念。在C语言中,标准输入和输出通常指的是键盘和屏幕,但它们也可以重定向到文件或其他设备。

一、什么是标准IO?

  • C库中定义了一组用于输入input 和输出outout的函数
  • 只能操作普通文件
  • FILE结构体描述文件信息,FILE*被称为对文件的操作都是围绕流进行的
  • 默认打开三个流
    • 标准输入 stdiin
    • 标准输出 stdout
    • 标准错误 stderr
  • 有缓存区

二、缓存区

标准I/O流有内置的缓冲机制,这意味着数据可能不会立即被写入磁盘或显示在屏幕上,而是先存储在缓冲区中,这样可以提高程序运行效率。
标准IO有三种缓存方式:行缓存、全缓存、不缓存

1.行缓存

行缓存和终端相关,如标准输出stdout
刷新条件:

  • 换行符\n刷新
  • 程序正常退出时刷新
  • 缓存区满刷新
    • 缓存区大小为 1KB(1024B)
      -强制刷新 fflush(NULL)

2.全缓存

全缓存和文件操作相关,如fprintf()
刷新条件:

  • 程序正常退出
  • 缓存区满刷新
  • 强制刷新fflush

3.不缓存

标准错误strerr 不缓存直接输出
标准错误它的主要用途是输出错误信息,这些信息不会被重定向,通常直接输出到屏幕,即使标准输出被重定向了。

三、文件相关函数

1.打开文件

FILE *fopen(const char *path, const char *mode);
功能:以只能方式打开对应文件
参数:
path:要打开路径下的文件,是个字符串
mode:打开方式,是个字符串
		r:只读,流被定位到文件开头
        r+:可读可写,流被定位到文件开头
        w:只写,文件不存在创建,文件存在清空,流被定位到文件开头
        w+:可读可写,文件不存在创建,文件存在清空,流被定位到文件开头
        a:追加,文件不存在创建,存在追加,流被定位到文件末尾
        a+:可读可写,文件不存在创建,存在追加,开始进行读时从头读,进行写时流
        注:这里所说的流其实就是文件中鼠标光标位置,流被定为在开头,就等于是光标在开头
返回值:
	成功 返回文件流
	失败 返回NULL,并且设置errno(错误码)
	

例子

    // 打开当前路径下的test文件,只读方式
    // 由FILE *类型的变量fp接收返回文件流
    FILE *fp = fopen("./test", "r");
    // 判断是否打开成功
    if (NULL == fp)
    {
        perror("read err\n");
        return -1;
    }

2.关闭文件

int fclose(FILE* stream);
功能:关闭文件
参数:
stream:文件流

3.文件读写

通过函数可以对文件进行读取或写入操作,但文件必须具有相应的读写权限(在打开文件的时候设置)

读写一个字符

读字符:
int fgetc(FILE *stream);
功能:
	从文件中读一个字符
参数:
	stream:文件流
返回值:
	成功:读到字符
    失败或读到文件末尾:EOF-1
写字符:
int fputc(int c, FILE * stream)
功能:向文件中写入一个字符
参数:
	c:要写的字符
   	stream:文件流
返回值:
	成功:写的字符的ASCII
    失败:EOF
例子:
//读写一个字符
//当前目录下有一个test1文件,里面只有一个字符A
#include <stdio.h>
int main()
{
    // 打开当前路径下的test文件,可读写方式
    // 由FILE*类型的变量fp接收返回文件流
    FILE *fp = fopen("./test1", "r+");
    // 判断是否打开成功
    if (NULL == fp)
    {
        perror("read err\n");
        return -1;
    }
    // 读取一个字符
    int c = fgetc(fp);
    // 打印读取字符
    printf("读取到一个:%c\n",c);
    // 写一个字符,并判断是否成功
    c = 'B';
    if(fputc(c,fp) == EOF)
    {
        perror("fputc error");
        return -1;
    }else
    {
        printf("写入A\n");
    }
    //关闭文件
    fclose(fp);
    return 0;
}

执行结果:
在这里插入图片描述

补充:

fgetc()的返回值并不能区别是读取失败还是读到文件末尾。如要区分需要使用一下两个函数

int ferror(FILE* stream)
功能:判断读文件时是否出错
返回值:非0表示错

int feof(FILE* stream)
功能:读文件时是否读到文件末尾
返回值:非0表示读到文件末尾

读写一个字符串

读字符串
char *fgets(char *s, int size, FILE *stream);
功能:从文件中读取一串字符
参数:
	s:存放读取的字符串的首地址(可以是一个char类型的字符串数组)
    size:读取的大小,实际读取大小为size-1,因为字符串末尾自动补'\0'
    stream:文件流
返回值:
	成功:读取的字符串的首地址
    失败或读到文件末尾:NULL
特性:
	1.一次调用最多读取一行数据
    2.实际读到个数为size-1个,末尾自动添加'\0'
写字符串
int  fputs(const char *s,  FILE *stream);
功能:向文件中写字符串
参数:
	s:要写的内容 (可以是char类型的字符串数组)
    stream:文件流
返回值:
	成功:非负整数
    失败:EOF
例子:
//读写一个字符串
//当前目录下有一个test1文件,里面有字符AB
#include <stdio.h>
int main()
{
    // 打开当前路径下的test文件,可读写方式
    // 由FILE*类型的变量fp接收返回文件流
    FILE *fp = fopen("./test1", "r+");
    // 判断是否打开成功
    if (NULL == fp)
    {
        perror("read err\n");
        return -1;
    }
    // 读取一字符串
    char s[3] = "";
    // 要读取AB两个字符,则要设置大小为3,因为字符串末尾自动补'\0'
    fgets(s,3,fp);
    // 打印读取字符
    printf("读取到一个:%s\n",s);
    // 写一个字符串,并判断是否成功
    if(fputs(s,fp) == EOF)
    {
        perror("fputc error");
        return -1;
    }else
    {
        printf("写入一个%s\n",s);
    }
    //关闭文件
    fclose(fp);
    return 0;
}
二进制读写

以二进制的方式进行读写,可以读写任意类型的数据。

//读
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 :要读取的文件
返回值:
	成功:写的元素个数
    失败 :0

fprintf

fprintf 函数是C语言中的一个标准库函数,用于格式化输出到流中。它通常用于将格式化的字符串写入到文件或标准输出(如屏幕)。
fprintf 的功能类似于 printf 函数,但是 printf 是输出到标准输出流(通常是屏幕),而 fprintf 可以指定输出到任何流。

int fprintf(FILE *stream, const char *format, ...);
参数:
	stream: 指向一个已经打开的文件流的指针。
	format: 一个格式控制字符串,与 printf 中的格式字符串相同,用来控制输出格式。
	...: 变长参数列表,提供要输出的数据。
比printf多了一个文件流,用来设定输出位置,其余功能与printf相同
fprintf(fp, "Name: %s, Age: %d\n", name, age); // 输出到文件
例子
//创建一个空文件test1
#include <stdio.h>
int main()
{
    // 打开当前路径下的test文件,可读写方式
    // 由FILE*类型的变量fp接收返回文件流
    FILE *fp = fopen("./test1", "r+");
    // 判断是否打开成功
    if (NULL == fp)
    {
        perror("read err\n");
        return -1;
    }
    char name[9] = "xiaoming";
    int age = 100;
    // 写一数据
    fprintf(fp, "Name: %s, Age: %d\n", name, age); // 输出到文件
	//关闭文件
    fclose(fp);
    return 0;
}

执行结果:
test1文件中多了fprintf打印的信息
在这里插入图片描述

文件定位(光标)操作

读写字符都是以光标位置作为起始位置,每次读写后,光标位置都会向后移动,读/写一个字符就往后移动一个单位
可以通过ftell获取指定文件当前光标的位置

long ftell(FILE *stream);
功能:
	获取位置指针当前的文件位置
参数:
	要检测的文件流
返回值:
	成功:当前的文件光标位置
	失败:-1

将光标移动到文件开头
void rewind(FILE *stream);
功能:将文件位置指针(光标)定位开头
如想将光标移动到指定的位置,使用fseek()函数
int fseek(FILE *stream, long offset, int whence);
功能:文件指针的定位操作
参数:
	stream:文件流
    offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移
    whence:相对位置:
           SEEK_SET:相对于文件开头
           SEEK_CUR:相对于文件当前位置
           SEEK_END:相对于文件末尾
返回值:成功:0
       失败:-1

以上叫法文件位置 流位置 都是指文件位置指针 通俗的讲就是文件中鼠标的光标位置
有人觉得叫光标太俗了所以取了很多奇怪的名字,都不如直接叫光标好理解。
我们还可以通过光标位置在计算文档中有多少字符

//相对文件末尾偏移0
 fseek(fp,0, SEEK_END);
//再获取光标位置
long len = ftel(fp);

总结

标准输入、输出和错误是C语言中处理数据输入和输出的基础。理解它们的工作原理对于编写健壮的程序至关重要,尤其是在处理用户交互和文件操作时。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值