标准IO

本文详细介绍了标准IO库在不同操作系统中的应用,包括FILE结构、缓冲机制、标准输入输出流以及关键函数如fopen、fclose、fread、fwrite等的使用。重点讲解了缓冲IO、行缓冲、全缓冲和无缓冲的概念,以及如何通过标准IO实现跨平台文件操作的流程和设置。
摘要由CSDN通过智能技术生成

标准IO:
在每个操作系统下,对于文件的处理方式、代码是不同的。
linux : open/read/
win : Winopen…
使用系统IO写代码,移植性很差。使用标准IO 能在不同的操作系统中实现需要的功能。在这里插入图片描述
在标准IO库,用一个结构体(FILE)来描述或表示一个普通文件,然后再这个结构体中创建了两个缓冲区(两端内存),一个读缓冲区,一个写缓冲区。

FILE
{
	char * in; //指向读的缓冲区的
	char * out;//指向写的缓冲区的
	...
	...
}

对“文件”操作的接口函数:

	fopen/fclose/fread/fwrite/fseek...
	puts/gets/fputs/fgets/printf/scanf....

APP通过标准IO操作文件的流程:

	APP -》 标准IO库 -> 对应平台的系统IO  -> OS(内核)  ->Hardware

FILE 有两个缓冲区(标准IO库开辟的两段内存)

	*in -----> 读的缓冲区 
	*out ----> 写的缓冲区 
缓冲区: 
	标准IO带缓冲IO, IO流,它的速率要比系统IO要高 。		
	系统IO: 
		read 1B  从硬盘读一个字节			
	标准IO: 
		fread 1B ,它会从硬盘读一块(512B)出来,放到
		标准IO的读缓冲区	
标准IO缓冲区有三种类型:
	行缓冲:
		数据达到一行啦,同步到外设上面去。
		假设您设置一行最多80字节。
		遇到了\n(换行符,一行结束的标志)
		当你缓冲区里面有了80个字节的数据啦,这个时候也会同步到外设上面去。
		printf 
	全缓冲:
		缓冲区中的数据要填满整个缓冲区,才同步到外设上去。		
	无缓冲:
		缓冲区有一个字节,就会同步到外设。			
		perror -> 无缓冲 			
	对于缓冲区也是可以自己去设置(setbuf)

系统IO:操作系统会自动的为每一个进程打开三个文件:

	标准输入文件  文件描述符   STDIN_FILENO  (0)
	标准输出文件  文件描述符   STDOUT_FILENO (1)
	标准出错文件  文件描述符   STDERR_FILENO (2)

标准IO库,会自动为每一个进程,打开三个标准io流(文件):

	标准输入流: FILE * stdin    	    //scanf() <------ stdin 
		stdin是定义在<stdio.h>中的一个全局变量,它指向
		标准输入设备(一般为终端或键盘)			
	标准输出流: FILE * stdout     //printf()  <------  stdout 
		stdout是定义在<stdio.h>中的一个全局变量,它指向
		标准输出设备(一般为控制台,终端或屏幕)		
	标准出错: FILE * stderr          //perror() <---- stderr 
		stderr是定义在<stdio.h>中的一个全局变量,它指向
		标准出错设备(一般为终端)

2.标准IO的函数接口

1.打开关闭一个IO流   用来打开一个普通文件(文本文件/二进制文件)
	函数原型:	
		FILE *fopen(const char *pathname, const char *mode);
	函数参数: 
		pathname:要打开的那个文件的文件名(带路径)
		mode: 打开文件的方式,有如下几种方式: 	
			"r" : 只读打开。 文件不存在,则报错;打开后,光标在文件开头。			
			"r+" : 读写打开。 文件不存在,则报错;打开后,光标在文件开头。	
			"w"  : 只写打开。文件不存在,则创建,打开后,文件内容截短(文件内容被清空)
			"w+" : 读写打开。文件不存在,则创建,打开后,文件内容截短(文件内容被清空)。
			"a"  : append 追加打开(只写打开)。 文件不存在,则创建 打开后,光标在文件末尾。文件内容不会被截短。	
			"a+" : 读写打开。文件不存在,则创建 ;
					原始读的位置在文件开头,原始写的位置在文件末尾
					(只有一个光标,打开后如果先读,光标在文件开头;如果先写,光标在文件的末尾)		
	返回值: 
		成功返回打开文件指针。 FILE * 
			在标准IO中,FILE*代表一个已经打开的文件,后续的
			标准io库的函数都需要用到它。
	失败返回NULL,同时errno被设置。
2.关闭IO流
	函数原型 :
		int fclose(FILE * stream);
			stream : 你想要关闭的那一个文件流
			返回值:成功返回 0 
						  失败返回-1,同时error 被设置
3.读写一个文件
	一旦读写成功,光标就会挪动到读写的位置。
	a.每次读写一个字节
		fgetc / getc /  getchar
		fputc / putc / putchar
		>>>>>>>>>>>      读    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		函数原型: 
		   int fgetc(FILE *stream);
		函数参数: 
			stream: 指定您想要到那个文件里面去读
		返回值: 、
			成功返回读到的那个字符的ASCII 
			失败返回-1,同时errno被设置。
		------------------------------------------------------------------------------------
			getc和fgetc一样,也是用来从stream指定的文件流中
			读取一个字符,并将读到的那个字符的ASCII返回。
			getc和fgetc那么它们的区别? 
				fgetc是一个函数,
				getc可能是用宏来实现的
		函数原型:		
			int getc(FILE *stream);
		函数参数: 
			stream: 指定您想要到那个文件里面去读
		返回值:
			成功返回读到的那个字符的ASCII 
			失败返回-1,同时errno被设置。
		------------------------------------------------------------------------
			getchar是用来从标准输入流(stdin)中获取下一个字符,
			并将读到的那个字符的ASCII返回。
		   	int getchar(void);
			getchar() <=> fgetc(stdin)
			<<<<<<<<   写  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
		fputc用来把c指定的字符,输出到stream指定的文件流。
		函数原型:
			int fputc(int c, FILE *stream);
		函数参数:
			c: 要输入到文件流中去的那个字符的ASCII
			stream: 指定您想要输入到哪个文件流中去
		返回值: 
			成功返回实际写入到文件流中的字符的ASCII
			失败返回-1,同时errno被设置。			
		----------------------------------------------------------------------------
			putc和fputc是一样的,功能一样,返回值,参数全都一样
			但是putc可能是用宏来实现的。
			int putc(int c, FILE *stream);
		-----------------------------------------------------------------------------
			putchar用来把c指定的字符,输出到标准输出文件流中
			putchar(c) <=> fputc(c, stdout)
			int putchar(int c);
	b.每次读写一行
		fgets / gets
		fputs / puts
		>>>>>  读  >>>>>>>>>>>>>>>>>>>>>>>>
		gets:
			函数原型:	
				char *gets(char *s);    //此函数未考虑到内存的大小,存在越界的风险
			函数参数:	
				s: 指向一个可写空间,用来保存从输入缓冲区读到的多个字符
			返回值: 
				成功返回s的首地址。
				失败返回NULL,同时errno被设置。
		-----------------------------------------------------------------------------
		fgets :
			函数原型:	
				char *fgets(char *s, int size, FILE *stream);
			函数参数: 
				s:指向的空间用来保存从文件流中去读的数据
				size: 表示您最多获取size个字节,size 一般是s指向的空间的可用长度。		
					fgets输入结束有两种情况:
						(1) 遇到\n或文件结束
						(2) 已经读取到了size-1个字节(后面留一个位置给\0)
				stream: 表示您从哪个文件流中去读	
		   	返回值: 
				成功返回s的首地址 
				失败返回NULL,同时errno被设置。
			>>>>>  写  >>>>>>>>>>>>>>>>>>>>>>>>
			
		fputs/puts 
			fputs把s指向的字符串,输出到stream指定的文件流。
		函数原型:
			 int fputs(const char *s, FILE *stream);
		函数参数: 
			s: 指向您要输出到文件流中去的字符串的首地址
			stream: 表示要输出到哪个文件流
		返回值: 
			成功返回非负数
			失败返回-1,同时errno被设置。
			-------------------------	
		puts :  用来把s指向的字符串,输出到标准输出流(stdout)中去,会多输出一个\n
		函数原型:
			int puts(const char *s);
		函数参数: 
			s: 指向您要输出到标准输出流中去的字符串的首地址
		返回值: 
			成功返回非负数
			失败返回-1,同时errno被设置。
			puts(s) => fputs(s, stdout) + putc('\n')
	c.直接任意读写,二进制读写
		fread / fwrite
		函数原型:
			size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
		函数参数: 
			ptr: 指向的内存空间,用来保存从文件流读取到的数据"数组"
			size: 每一个元素占字节大小
			nmemb:要读取n个元素
			stream:表示您要到哪个文件流中去读
		返回值: 
			成功返回实际上读到的元素的个数!!!  <= nmemb
			失败返回-1,同时errno被设置。
			----------------------------------------------------
			fwrite用来把ptr指向的n个元素(每一个元素占size字节)写到stream指向的文件流中去。
		函数原型:
			size_t fwrite(const void *ptr, size_t size, size_t nmemb,
					 FILE *stream);
		函数参数: 
			ptr: 指向的空间,用来保存您将要写入的内容
			size: 每一个元素的大小
			nmemb : 要写入多少个元素
			stream: 您要写入到哪个文件流中去	
		返回值:	
			成功返回实际写入到文件流中的元素个数 。 <= nmemb
			失败返回-1,同时errno被设置。
4.冲洗一个文件流
	把缓冲区的内容做一次与硬件的同步
	函数原型:			
		int fflush(FILE * stream);
			stream:要同步的那一个流。
			返回值:
				成功返回0
				失败返回-1,同时error被设置
				注意: 
					对于输出流,fflush把写缓冲区的内容写/更新到文件中去
					对于输入流,fflush把读缓冲区的内容直接丢弃。
						so下一次读就会重新文件中去读取内容。
					stream为NULL,fflush把该进程所有的打开的输出文件流同步。

5.定位文件流
	文件偏移量”: offset 光标。 文件读取到的位置。
	fseek用来定位一个文件流的光标位置的
		函数原型:
			 int fseek(FILE *stream, long offset, int whence);
		函数参数:
			stream: 文件流指针,您要定位的是那一个文件。
			offset:偏移量,具体含义与第三个参数相关:
			whence: 光标的定位方式:
					SEEK_SET : 基于文件开头定位
								新光标的位置 = 文件的开头 + offset			
					SEEK_CUR : 基于光标的当前位置定位
								新光标的位置 = 当前位置 + offset(可正可负)
					SEEK_END : 基于文件末尾定位
								新光标的位置 = 文件的末尾 + offset(可正可负)
			返回值: 
					成功返回0
					失败返回-1,同时errno被设置。 
		函数:
	 	  ftell返回当前位置离文件开头有多少个字节。		
		  long ftell(FILE *stream);
		  rewind把文件光标,定位在文件开头。
		  void rewind(FILE *stream);
 6.文件出错/文件结束标志
 	EOF: End Of File 文件结束标志 “宏”
	feof:判断stream指向的文件流是否结束
	函数原型: 
		 int feof(FILE *stream);
	函数参数:
		stream
	返回值: 
		返回真(非0) 如果文件达到末尾啦
		返回假(0)   如果文件还没有达到末尾啦	
	NOTE: 
		标准IO库,在读到文件末尾时,会往缓冲区填入EOF
		EOF 二进制 11111111
7. 格式化输出/输入
	7.1) 格式化输入 
		scanf/sscanf/fscanf 
		"格式化输入" : 按照我指定的格式来输入
	   int scanf(const char *format, ...);
		scanf可以带很多参数,scanf参数一般分为两类:
		第一个参数为第一类参数:格式化字符串
			“格式化字符串”就是告诉用户该怎么输入参数,你得
			按照它所指定的格式去进行输入。
			在“格式化字符串中有三类字符”:
			a、空白符(空格 tab。。)
				指示用户 您可以输入任意多个空白符(包含0)scanf是\n当作输入结束.
			b、非转义字符
				(普通字符,除了空白符和%意外的字符)
				精准匹配,您得原样输入
			c、转义字符(以%开头的)
				%d -> [0-9]+
				%c -> 匹配一个字符(可以输入的字符)
				%f -> 浮点数
				%s -> 字符串(不带空白符,scanf会把空白符当作是分隔符)
				...		
		其它参数为第二类参数,地址列表: 
			格式化字符串中一个转转义字符会对应一个地址,把一个
			转义字符的输入存储到指定的地址中去。
			如果转义字符的个数 多于 地址个数,程序行为是Undefined 
			scanf获取输入时,从stdin的缓冲区中获取输入,输入何时结束?
				a、该用户的都输入完啦 
					scanf("abcd%d  %c1234", &a, &b);
					用户输入: 
						abcd1234A1234  -> 该用户的都输入了 , scanf结束
				b、 匹配失败
					scanf("abcd%d %c123", &a, &b);
					用户输入:
						ABCD -> scanf停止匹配
		返回成功匹配到的变量的个数。
		r = scanf("%d%c",&a, &c);
			123B456 
			a = ?123
			c = ? B 
			r = ? 2
	------------------------------------	------------------------------------	
	int sscanf(const char *str, const char *format, ...);
		sscanf它的功能以及函数的返回值都是和是一样的,只不过sscanf的输入来源不是stdin,而是来自str指向的哪个字符串
		sscanf三类参数: 
			str: 输入字符串的来源
			format:是格式化字符串 
			.... : 地址列表 
				const char * str = "1234BCDDDD"
				int r,a;
				char c;
				r = sscanf(str, "%d %c", &a, &c);
				a = 1234
				c = B
				r = 2
		------------------------------------------------------------------------------------			
	 	int fscanf(FILE *stream, const char *format, ...);
		fscanf它的功能还有返回值都是scanf一样,只不过fscanf它的输入从stream指向的那一个文件流中去获取。
		fscanf参数三类: 
			stream: 指向的哪个文件流
			format:是格式化字符串 
			.... : 地址列表 
		fscanf(stdin, fromat, ...) <=> scanf(format, .....)
7.2 )格式化输出 
		printf/sprintf/fprintf/snprintf
		"格式化输出" : 按照您自己指定的格式输出
	   int printf(const char *format, ...);
			printf可以带两类参数:
			(1) 格式化字符串:就是告诉你按照什么样的格式输出
				a、转义字符:以%开头的字符 \n 
					%d   %u  %ld  %lu 	%f 	%c 	%s 
					.....
				b、非转义字符
					原模原样的输出		
			(2) 要输出的对象的地址列表		
				要输出的变量或对象的个数  应该与 转义字符(%)的个数一致
				返回值: 
					实际打印的字符的个数
	------------------------------------------------------------------------------------		
	   int fprintf(FILE *stream, const char *format, ...);
			fprintf它的功能和返回值,和printf一样,只不过fprintf输出不是输出到stdout,而是输出到stream指向那个文件流中。
			fprintf有三类参数:
				stream: 指向输出的文件流
				format: 格式化字符串 
				.....:  要输出的对象的地址列表
			返回值: 
				实际输出到文件流中去的字符的个数
	------------------------------------------------------------------------------------		
	   int sprintf(char *str, const char *format, ...);
			sprintf它的功能和返回值,和printf一样,只不过sprintf输出不是输出到stdout,而是输出到str指向那个内存中去。
			sprintf有三类参数:
			str: 指向您要输出的地址
			format: 格式化字符串 
			.....:  要输出的对象的地址列表
			返回值: 
				实际输出到内存中去的字符的个数		
			sprintf存在越界的风险!
	   int snprintf(char *str, size_t size, const char *format, ...);
			snprintf它的功能,和sprintf一样,只不过snprintf限制了大小。
			sprintf有四类参数:
				str: 指向您要输出的地址s
				size: szie是str指向的那段内存的最大长度,顶多输出size-1个字符到str中
			 	format: 格式化字符串 
				.....:  要输出的对象的地址列表
			返回值:
					返回应该输出的字符串的长度,而不是实际
					上输出字符串的长度
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值