IO——标准IO

发布于:2024-04-16 ⋅ 阅读:(20) ⋅ 点赞:(0)

1.1概念

在这里插入图片描述

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

1.2特点

(1)通过缓冲机制减少系统调用,提高效率
(2)围绕流操作,用FILE*描述
(3)标准IO默认打开三个流,stdin,stdout,stderr

1.3缓存区

(1)全缓存,和文件相关
全缓存表示当缓存区填满时才进行写入操作
(2)行缓存,和终端相关
表示当换行时才进行写入操作
(3)不缓存,标准错误,没有缓存,直接输出
刷新标准输出缓存区的条件
(1)程序正常退出
(2)缓存区满
(3)\n,换行操作
(4)强制刷新 fflush(NULL)
例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    //printf("hello world\n"); //\n不光可以换行,还可以刷新标准输出的缓冲区
    printf("hello world");
    fflush(NULL); //强制刷新缓存区
    while (1);//让程序无法正常结束
    return 0;  //正常退出刷新刷存区
}

标准输出缓存区大小
1kb
在这里插入图片描述
缓存区存了256个int字符,共256*4=1024b=1kb

1.4函数接口

1.4.1打开fopen

FILE* open(const charpath,const charmode)
功能:打开文件
参数:
path:打开的文件路径
mode:打开的方式
r:只读,当文件不存在时报错,文件流定位到文件开头
r+:可读可写,当文件不存在时报错,文件流定位到文件开头
w:只写,文件不存在创建,存在则清空
w+:可读可写,文件不存在创建,存在则清空
a:追加(在末尾写),文件不存在创建,存在追加,文件流定位到文件末尾
a+:读和追加,文件不存在创建,存在追加,读文件流定位到文件开头,写文件流定位到文件末尾
注:当a+的方式打开文件时,写只能在末尾进行追加,定位操作是无法改变写的位置,但是可以改变读的位置
返回值:
成功:文件流
失败:NULL,并且会设置错误码

1.4.2关闭文件fclose

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

#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    //1.打开文件
    //fp = fopen("test.txt","w");
    fp = fopen("test.txt", "r");
    if (NULL == fp)
    {
        perror("fopen err"); //如果以r方式打开,没有这个文件会报错,打印错误信息。
        return -1;
    }
    printf("fopen success\n");

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

    return 0;
}

1.4.3 文件读写操作

1.4.3.1读写一个字符fgetc() fputc()

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

#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    //1.打开文件
    fp = fopen("test.txt", "r+");
    //fp = fopen("test.txt", "r");
    if (NULL == fp)
    {
        perror("fopen err"); //如果以r方式打开,没有这个文件会报错,打印错误信息。
        return -1;
    }
    printf("fopen success\n");

    //对文件读写操作
    char ch = fgetc(fp);
    printf("%c %d\n", ch, ch);//h 104

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

    fputc('a', fp);
    fputc(98, fp);

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

    return 0;
}

针对终端

#include <stdio.h>

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

    ch = fgetc(stdin);
    //printf("%d %c\n", ch, ch);
    fputc(ch, stdout);

    return 0;
}

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

fp = fopen("test.txt", "w");//权限设置为写
    if (NULL == fp)
    {
        perror("fopen err"); 
        return -1;
    }
    printf("fopen success\n");

    char ch = fgetc(fp); //因为权限是只写,所以读操作有错误。
    if (ferror(fp))
    {
        printf("err!\n");
        return -1;
    }

1.4.3.2读写字符串fgets() fputs()

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

int fputs(const char *s, FILE * stream);
功能:向文件中写字符串
参数:s:要写的内容
stream:文件流
返回值:成功:非负整数
失败:EOF

注意: fgets输入时最后一定有一个位置给\0

1.4.3.3二进制读取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 : 要进行写入元素的个数
strem: 目标文件流指针
返回值:成功:写的元素个数
失败 :-1

1.4.4其他操作

1.4.4.1重定向freopen()

FILE * freopen(const char *pathname,  const char *mode,  FILE* fp);
功能:将指定的文件流重定向到打开的文件中
参数:path:文件路径
     mode:打开文件的方式(同fopen)
     fp:文件流指针
返回值:成功:返回文件流指针
      失败:NULL
      
#include <stdio.h>
//例子
int main(int argc, char const *argv[])
{
    printf("hello\n");
    //将标准输出重定向到打开的test.txt中
    freopen("test.txt", "w+", stdout);
    printf("world\n");

    //将标准输出流重定向到终端文件/dev/tty
    freopen("/dev/tty", "r+", stdout);
    printf("66666\n");

    return 0;
}

1.4.4.2定位操作rwind() fseek() ftell()

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

总结:

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