12.2 IO(2)

这篇继续说一下IO中常见的函数以及标准IO的机理。
内容在书13.4,13.5,13.6章。

1 文件IO函数

上一篇介绍的函数都类似于文件IO函数。主要区别在于文件IO需要用FILE*指定待处理的文件。
而接下来介绍的函数则使用 指向FILE的指针(如stdout)指定一个文件。

1.1 fprintf_s()与fscanf_s()

这两个函数的工作方式与printf()和scanf()类似,区别在于这两个函数的第一个参数需要指定待处理的文件

1.1.1 将键盘输入的文字记录至磁盘并从磁盘中读出再输出

//将键盘输入内容写入到磁盘再读取并输出
#include 
#include 

#define LENGTH 128

int main(void)
{
     
	char out[] = "J:\\IO_Write\\keyboard.txt";
	show_write_keyboard_input(out);
	return 0;
}

int show_write_keyboard_input(char* path)
{
     
	FILE* out;
	char file_name[LENGTH];
	char string[LENGTH];
	printf("请在看到这一行字之后开始输入文字,若输入#则代表结束输入。\n");
	strncpy_s(file_name, LENGTH - 8, path, LENGTH - 8);
	file_name[LENGTH - 8] = '\0';
	fopen_s(&out, file_name, "a+");//a+:追加模式
	while ((fscanf_s(stdin, "%s", string, 120) == 1) && string[0] != '#')//第一个字符为#则中断输入
	{
     
		fprintf_s(out, "%s", string);
	}
	rewind(out);//指针返回文件开始处
	printf_s("现在开始输出刚才从键盘输入的内容:\n");
	while (fscanf_s(out, "%s", string, 120) == 1)
	{
     
		fprintf_s(stdout, "%s\n", string);
	}

	return 0;
}

运行结果

请在看到这一行字之后开始输入文字,若输入#则代表结束输入。
g4f1g1f1g1f1f1
fdsdgd544651
411fdsggffsg#46465
#
现在开始输出刚才从键盘输入的内容:
g4f1g1f1g1f1f1fdsdgd544651411fdsggffsg#46465

1.2 fgets()与fputs()

下面的表格简单的对比了这两个函数。

函数 参数 返回值
fgets() char*,待输入字符串大小(int), FILE* char*
fputs() char*, FILE* int

fgets()将会读取输入直到第一个换行符的后面,或文件结尾,或STRLEN-1个字符。随后会在字符串末尾添加一个空字符表示这是一个字符串。在读取到EOF时会返回NULL

**fputs()**与puts()的不同在于,fputs()在输出字符串时不会在末尾为其添加换行符。

2 随机访问

2.1 fseek()与ftell()

fseek()可以将文件看成一个数组,在fopen()打开的文件中移动到任意字节处。
ftell() 则是用于得到文件位置指针当前位置相对于**文件首的偏移**字节数

2.1.1 倒序输出文件的内容

#include 
#define LENGTH 128

int main(void)
{
     
	//文件内容是26个字母小写a-z,大写A-Z,数字1234567890
	char path[] = "J:\\IO_Write\\random.txt";
	random_read_input(path);
	return 0;
}

int random_read_input(char* path)
{
     
	FILE* in;
	char input[LENGTH];
	char c;
	long count, last;
	strncpy_s(&input, LENGTH - 8, path, LENGTH - 8);
	input[LENGTH - 8] = '\0';
	fopen_s(&in, input, "r");

	fseek(in, 0L, SEEK_END); //定位到文件末尾
	last = ftell(in);

	for ( count = 1L; count <= last; count++)
	{
     
		fseek(in, -count, SEEK_END); //从最后往最前面读取
		c = getc(in);
		putchar(c);
	}
	printf("\n");
	fclose(in); //关闭文件
	return 0;
}

运行结果

0987654321ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba

2.1.2 fseek()的工作原理

可以通过下面的表格对比一下这两个函数。

函数 参数 返回值
fseek() FILE*, 偏移量(long), 模式(int) int
ftell() FILE* long

对于fseek()中的偏移值,可以是证书,可以是负数,也可以是0,但是必须加上L转换为long类型。
第三个参数,则是确定起始点。下面是C语言预定义的常量。

模式 偏移量起始点 旧实现的替代值
SEEK_SET 文件开始处 0L
SEEK_CUR 当前位置 1L
SEEK_END 文件结尾 2L

看看下面的函数,想想代表了什么。

fseek(in, 10L, SEEK_SET); //定位至文件开始第10字节
fseek(in, -5L, SEEK_CUR); //定位至当前位置后第5字节
fseek(in, -15L, SEEK_END); //文件结尾处回退15字节

2.2 fgetpos()与fsetpos()

这两个函数主要是解决fseek()与ftell()的文件大小只有long范围的问题。
这两个函数用fpos_t代替了原来的long类型。

3 标准IO的机理

对于文件的IO,第一步操作一般都是使用fopen_s()打开文件,该函数同时还创建了一个缓冲区

第二步则是通过输入函数读取内容,可能是标准输入流,也可能是一个文件。一旦调用这些函数,文件的数据块就会被拷贝至缓冲区。缓冲区的大小在不同的实现中有不同的数值,一般都是512字节的倍数。最初调用时,除填充缓冲区之外,还需要设置FILE*指向结构的值。

初始化完成并已经将缓冲区所有字符读取完毕后,会将下一块缓冲区大小的数据读取至缓冲区,重复上面的操作直至将整个文件读取完毕。

输出函数操作与读取输入操作相反,当缓冲区被填满时,数据将会被拷贝至文件中

你可能感兴趣的:(C语言学习)