我们已经有系统IO了,为什么还需要标准IO呢?每个系统写出来都不一样,windows有windows的搞法linux有linux的搞法.....但是他们有一个共通点 --- 都是c写的c就讲既然你们都是用我写的,那么我就得统一你们,这样我们的开发就变得简单很多只要是支持c的系统都可以采用标准IO来处理文件系统文件没有办法,只能按照系统io的搞法普通文件的处理用标准io规定 --- 以后的普通文件都采用标准io处理,系统级的文件采用系统io标准io采用一个叫文件流的东西来表示这个打开的文件typedef struct{char in[1024];//输入缓冲区char out[1024];//输出缓冲区......}FILE;输入缓冲区:系统io在硬盘里面读一个字节,那么就去硬盘读一个字节FILE就不这么干,在硬盘上面读一个字节,标准IO会直接读一行数据(1024字节)你现在不是需要一个字节吗,那么我就在缓冲区里面给你一个字节对于用户来讲,它拿到的这个字节是在缓冲区里面拿的,因此对于用户来讲去缓冲区里面拿取数据明显要快一些输出缓冲区:FILE如果是写入,那么会首先写到这个缓冲区,当缓冲区里面有大量的数据或者强制同步的时候才会往我们硬盘写入缓冲区有几种1 行缓冲必须要往这个缓冲区里面写满一行才会同步到文件(fflush强制同步另算)printf就是一个行缓冲2 全缓冲必须将缓冲区全部填满才会同步到文件3 无缓冲只要往缓冲区里面写入字节就会同步到文件比较紧急的情况下面我们一般采用无缓冲perror在运行我们的程序的时候,系统会自动给我们打开三个文件FILE * stdin;//标准输入FILE * stdout;//标准输出FILE * stderr;//标准出错标准IO处理文件打开文件fopen
NAMEfopen, fdopen, freopen - stream open functionsSYNOPSIS#include <stdio.h>FILE *fopen(const char *pathname, const char *mode);FILE *fdopen(int fd, const char *mode);pathname:打开的文件的路径名fd:用文件描述符来表示你打开的这个文件mode:以什么方式打开这个文件,本质是一个字符串"r":只读打开,文件不存在则报错,打开后光标默认在开头"r+":读写打开,文件不存在则报错,打开后光标默认在开头"w":只写打开,文件不存在则创建,打开后文件的内容会被清空,光标在开头"w+":读写打开,文件不存在则创建,打开后文件的内容会被清空,光标在开头"a":追加打开,文件不存在则创建,打开后光标在末尾"a+":读写打开,文件不存在则创建,原始读在开头,原始写在末尾返回值:成功返回FILE * 指针,后续对于这个文件的操作都是基于这个指针失败返回NULL,同时errno被设置NAMEfclose - close a stream关闭一个文件流
SYNOPSIS#include <stdio.h>int fclose(FILE *stream);stream:你要关闭哪个流读写文件一次读写一个字节
NAMEfgetc, fgets, getc, getchar, ungetc - input of characters and stringsSYNOPSIS#include <stdio.h>int fgetc(FILE *stream);//这个玩意儿是一个函数int getc(FILE *stream);//它是一个宏stream:你要在哪个文件流里面获取一个字节获取到的这个字节都是通过返回值返回给你的int getchar(void);//直接在stdin里面获取一个字符getchar() <-> fgetc(stdin)NAMEfputc, putc, putchar - output of characters往文件流里面写入一个字节
SYNOPSIS#include <stdio.h>int fputc(int c, FILE *stream);//函数int putc(int c, FILE *stream);//宏int putchar(int c);//直接往stdout里面写入 putchar('A')<->fputc('A',stdout)c:你要写入的这个字符stream:你要往哪个文件流里面写入返回值:成功的时候c是什么返回的就是什么,失败返回-1文件读完,会自动往缓冲区里面填上一个字节 1111 1111 -> EOF练习:使用fopen的多种打开形式r r+ w w+ a a+往一个文件里面写入一个字节之后,弄一个while(1);看看这个字节有没有弄到文件里面去用一次搬一个字节的方式,采用标准io拷贝一个文件fp_from = fopen("1.txt","r");fp_to = fopen("2.txt","w");while(1){char c = fgetc(fp_from);if(c == EOF){break;}fputc(c,fp_to);}读写一行char *gets(char *s);//直接在stdout里面获取 这个函数有哦bug 可能会让s越界 不建议使用char *fgets(char *s, int size, FILE *stream);//指定在哪个文件流s:你获取到的数据放在哪个内存size:你要获取多少个字节stream:文件流成功返回s,失败返回NULL,同时errno被设置写一行数据到文件流int fputs(const char *s, FILE *stream);int puts(const char *s);//直接往stdout里面写入puts("abcd") <-> fputs("abcd",stdout)s:写入的数据stream:文件流返回值:puts() and fputs() return a nonnegative number on success, or EOF onerror.指定字节去读,读二进制NAMEfread, fwrite - binary stream input/output二进制的读写
SYNOPSIS#include <stdio.h>size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);ptr:你要读到哪个内存size: 你的一个元素有多少个字节nmemb: 你有多少个元素stream:文件流size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);ptr:你要写入的内容size: 你的一个元素有多少个字节nmemb: 你有多少个元素stream:文件流成功返回实际读写的元素个数 <= nmemb,失败返回-1,同时errno被设置NAMEfgetpos, fseek, fsetpos, ftell, rewind - reposition a streamSYNOPSIS#include <stdio.h>int fseek(FILE *stream, long offset, int whence);//偏移stream:文件流offset:偏移量 跟lseek一样whence:基准定位方式SEEK_SET 开头SEEK_CUR 当前位置 SEEK_END 末尾成功返回0 失败返回-1,同时errno被设置(这里跟lseek不一样了)long ftell(FILE *stream);//返回光标的位置到文件开头所有的字节数fseek(fp,0x00,SEEK_END);long filesize = ftell(fp);//求文件的大小void rewind(FILE *stream);//直接将光标定位到开头//刷新缓冲区让流的缓冲区强制同步对于输入流来说:fflush直接丢弃里面没有拿取完的数据(stdin比较特殊,fflush(stdin)可能会没有效果)对于输出流来说:fflush会将没有同步到文件的数据强制同步到文件程序如果正常结束,操作系统会自动给我们把所有的流都刷新如果出现非正常死亡,如段错误,这个时候就不会刷新流了NAMEfflush - flush a stream 刷新一个流
SYNOPSIS#include <stdio.h>int fflush(FILE *stream);stream:你要刷新哪个文件流你可以填NULL,表示所有的流练习:用fread fwrite写一个copy文件,然后将我们的bmp文件处理改成fread格式化的输入输出给用于提供一个格式,用户通过这个格式来进行输入输出就很简单NAMEscanf, fscanf, sscanf, vscanf, vsscanf, vfscanf - input format conver‐sion格式化输入
SYNOPSIS#include <stdio.h>int scanf(const char *format, ...);//直接从stdin里面获取int fscanf(FILE *stream, const char *format, ...);//从stream里面获取int sscanf(const char *str, const char *format, ...);//从str这个字符串里面获取stream:文件流str:一个字符串 你再这里拿取有效的数据format:格式化的字符串,里面的字符有三种1 空白符当成分隔符你可以输入多个空白符,它只会当成一个分隔符2 普通字符用来做匹配,你需要原模原样的输入进来才能进行匹配"abc%d" 你在输入的时候就必须先输入abc123 -> 这个时候%d才会匹配到1233 转义字符 %%d -> 整数%c -> 字符%f -> 浮点......%% -> %这个字符每写一个%号,后面的...里面就多一个地址scanf就是往这些地址里面写入数据的... :地址,个数与%号一一对应,除非是%%用,号隔开即可(参数)返回值:成功返回匹配到的个数,匹配是匹配转义字符,里面匹配几个就返回几个scanf("%d%d%c"); -> 输入:123c123 -> 这个时候没有全部匹配 只匹配了一个 那么它就返回1NAMEprintf, fprintf, dprintf, sprintf, snprintf, vprintf, vfprintf, vdprintf, vsprintf, vsnprintf - formatted output conversion格式化的输出
SYNOPSIS#include <stdio.h>int printf(const char *format, ...);//固定往stdout里面输出int fprintf(FILE *stream, const char *format, ...);int dprintf(int fd, const char *format, ...);int sprintf(char *str, const char *format, ...);//可能会造成str越界 因此建议使用下面的这个函数int snprintf(char *str, size_t size, const char *format, ...); stream:你要往哪一个文件里面输出 文件流fd:你要往哪个文件描述符代表的那个文件里面输出str:你要往哪个内存里面输出size:你要输出多少个字节format:格式化的字符串1 空白符2 普通字符空白符 和 普通字符会原封不动的输出3 转义字符 %%d -> 整数 -> 整形值%c -> 字符 -> 字符%f -> 浮点 -> 小数......%% -> %这个字符...:可变参数 与前面的%一一对应这种格式化的输入输出我们用于带格式的文件里面如一个文件里面保存了一些信息前面是name 再是addr 接下来是age penglei changsha 18xiaoming zhongguo 45......