文件与文件操作

目录

1.文件?

1.程序文件

2.数据文件

 3.文件名

2.为什么使用文件?

3.二进制文件和文本文件

4.文件的打开和关闭

1.流和标准流

2.文件指针

 3.文件的打开和关闭

4.fopen

5.fclose

6. 实现文件打开和关闭(伪代码):

5.文件的顺序读写

 1.fgetc

 2.fputc

 3.fgets

4.fputs

5.fscanf

6.fprintf

7.fread

8.fwrite

6.文件的随机读写

1.fseek

2.ftell

3.rewind

7.文件读取结束的判断

1.feof

2.ferror

8.文件缓冲区

1.文件缓冲区?

2.缓冲区与流的关系

3.完全缓冲

4.缓冲区刷新(fflush)


1.文件?

文件就是磁盘或者硬盘上的文件。文件有很多种类,有文本文件,数据文件,程序文件,图像文件,压缩文件……在程序设计中,我们一般接触的是程序文件和数据文件。

1.程序文件

程序文件包括源程序文件(后缀.c),目标文件(Windows环境后缀.obj),可执行文件(Windows环境后缀.exe)。源文件是程序员编写的源代码文件,其中包含了程序的逻辑和算法。目标文件是编译器将源文件编译后生成的中间文件,其中包含了汇编代码和符号表等信息。可执行文件是链接器将目标文件链接后生成的最终可执行文件,其中包含了机器码和程序入口点等信息。即在编译过程中,编译器将源文件编译成目标文件,链接器将目标文件链接成可执行文件。可执行文件可以在操作系统中直接执行,完成程序的功能。

2.数据文件

在程序设计中,开发人员通常会使用文件输入/输出操作来读取和写入数据文件的内容。这可以包括使用文件流、读取和写入文本文件、二进制文件、JSON文件、XML文件等不同的技术和格式。

 3.文件名

文件名即为一个文件唯一的文件标识(比作身份证),以便用户识别和引用。

文件名包含三个部分:文件路径+文件名主干+文件后缀,比如:

c:\code\project.txt

 文件标识常被称为文件名;.txt为文本文件的后缀。 

 文件的后缀名决定了一个文件的默认打开方式;文件在命名时可以没有后缀名(不推荐这么做);文件名中不能包含这些字符:\/:*?"<>|等。

2.为什么使用文件?

我们在程序中进行的运算,操作等运行结果都会随着程序运行结束而跟着消失,如果要将数据进行持久化的保存,我们要将数据保存在文件中。

3.二进制文件和文本文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。通俗的来讲,文本文件就是人眼看得懂的内容,二进制文件一般来说是看不懂的。

 数据在内存中以二进制的形式存储,如果不加转换的输出到外存(外部存储设备),就是二进制文件。

如果要求外存以ASCII码的形式存储,则需要在存储前进行转换,以ASCII字符的形式存储的文件就是文本文件。

那么一个数据在内存中是怎么存储的呢?

字符一律以ASCII码的形式存储,数值型数据可以用ASCII形式或者二进制形式存储,比如有个整数10000,那么有下面的表示方式:

 下面代码进行演示:

#include <stdio.h>

int main()
{
	int a = 10000;
	FILE* pt = fopen("text.txt", "wb");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	fwrite(&a, 4, 1, pt);
	fclose(pt);
	pt = NULL;

	return 0;
}

 

 上述代码是以二进制形式将10000写进文件中,打开二进制文件发现为上面形式10 27 00 00是小端存储下的十六进制表示。

4.文件的打开和关闭

既然要对文件进行读写,那就要先打开文件,再进行大写,最后关闭文件(打开冰箱门,大象塞进去,关上冰箱门……)接下来将一步步揭开文件的面纱。

1.流和标准流

流: 我们程序的数据需要从外部设备获取数据,也会输出到外部设备,外部设备多种多样,输入输出的方式也各不相同,为了使用户对外部设备方便使用,就抽象出流的概念,流的概念是指在计算机编程中用于处理输入和输出数据的抽象概念。流可以是字节流或字符流,用于在程序中传输数据。流可以连接到各种输入和输出源,如文件、网络连接、内存等。一般情况下,我们要想向流里读写数据,需要打开流,然后操作。

内存中的流是一块连续的区域,用于存储数据或程序。

 标准流:C语言在程序启动时,默认打开了3个流:

a. stdin-标准输入流,在大多数的环境中从键盘输入,scanf函数就是从标准输入流中读取数据。

b. stdout-标准输出流,在大多数环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中。

c.stderr-标准错误流,大多数环境中输出到显示器界面。

既然是默认打开,那就解释在从键盘输入数据和向屏幕输出数据时我们并没有手动打开任何流却可以进行操作了。

stdin,stdout,stderr三个流的类型是:FILE* ,即为文件指针。

在C语言中,就是通过FILE*的文件指针来维护流的各种操作的。

2.文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,即为“文件指针”。

每个被使用的文件都会在内存开辟一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,重命名为FILE。每当打开一个文件,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息。

不同的C编译器的FILE类型包含内容不完全相同但大同小异。

既然FILE是一种结构类型,那么FLIE*指针类型的变量指向的是一个结构体变量,即指向某个文件的文件信息区,通过文件信息区中的信息就能访问该文件,也就是说通过FILE*类型的文件指针变量就能够间接找到与它关联的文件。

 3.文件的打开和关闭

文件在读写之前要先打开文件,读写结束要关闭文件。

在编写程序打开文件时,会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

在ANSIC中规定fopen函数来打开文件,fclose函数来关闭文件。

4.fopen

fopen-C参考 (cplusplus.com)

 简单来说,fopen接受两个参数,filename即为所要打开的文件名,mode表示文件的打开模式,打开成功函数返回一个指向文件信息区的FILE类型指针,NULL。

下面是一些mode:

文件使用方式               含义                             如果文件不存在 

“r”(只读)    为了输⼊数据,打开⼀个已经存在的⽂本⽂件       出错
 “w”(只写)   为了输出数据,打开⼀个⽂本⽂件                建⽴⼀个新的⽂件
 “a”(追加)   向⽂本⽂件尾添加数据                         建⽴⼀个新的⽂件
 “rb”(只读)  为了输⼊数据,打开⼀个⼆进制⽂件              出错
 “wb”(只写)  为了输出数据,打开⼀个⼆进制⽂件              建⽴⼀个新的⽂件
 “ab”(追加)  向⼀个⼆进制⽂件尾添加数据                    建⽴⼀个新的⽂件
 “r+”(读写)  为了读和写,打开⼀个⽂本⽂件                  出错
 “w+”(读写)  为了读和写,建议⼀个新的⽂件                  建⽴⼀个新的⽂件
 “a+”(读写)  打开⼀个⽂件,在⽂件尾进⾏读写                建⽴⼀个新的⽂件
 “rb+”(读写) 为了读和写打开⼀个⼆进制⽂件                  出错
 “wb+”(读写) 为了读和写,新建⼀个新的⼆进制⽂件             建⽴⼀个新的⽂件
 “ab+”(读写) 打开⼀个⼆进制⽂件,在⽂件尾进⾏读和写         建⽴⼀个新的⽂件 

5.fclose

fclose - C++ Reference (cplusplus.com)

6. 实现文件打开和关闭(伪代码):
#include <stdio.h>

int main()
{
	//打开文件
	FILE* pt = fopen("projece_1.txt", "w");
	//如果打开失败
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	//对文件进行操作\
	......
	//关闭文件
	fclose(pt);
	//将pt置为NULL,避免出现野指针
	pt = NULL;

	return 0;
}

 

5.文件的顺序读写

文件的顺序读写是指按照文件中数据的顺序进行读取或写入操作。顺序读取是从文件的开头开始依次读取数据,直到文件末尾;顺序写入是从文件的末尾开始依次写入数据,直到文件末尾。

既然打开了文件,那就可以对文件进行读写,对文件进行读写是通过特定的函数进行操作的,下面我们介绍几个相关的顺序读写函数:

注意:输入输出是对于内存来说的,要厘清关系。

函数名       功能           适⽤于

fgetc    字符输⼊函数      所有输⼊流
fputc    字符输出函数      所有输出流
fgets    ⽂本⾏输⼊函数    所有输⼊流
fputs    ⽂本⾏输出函数    所有输出流
fscanf   格式化输⼊函数    所有输⼊流
fprintf  格式化输出函数    所有输出流
fread    ⼆进制输⼊        ⽂件
fwrite   ⼆进制输出        ⽂件

 1.fgetc

fgetc - C++ Reference (cplusplus.com)

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_1.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	int c = fgetc(pt);
	printf("%d %c", c, c);

	fclose(pt);
	pt = NULL;

	return 0;
}

 

 

 由于每读取一个字符,内部文件光标都会向后移动一位,所以我们可以多次fgetc操作将其他字符也打印出来:

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_1.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	int c = fgetc(pt);
	printf("%d %c\n", c, c);
	c = fgetc(pt);
	printf("%d %c\n", c, c);
	c = fgetc(pt);
	printf("%d %c\n", c, c);
	c = fgetc(pt);
	printf("%d %c\n", c, c);
	c = fgetc(pt);
	printf("%d %c\n", c, c);
	c = fgetc(pt);
	printf("%d %c\n", c, c);

	fclose(pt);
	pt = NULL;

	return 0;
}

 

 原来文件就只有qwer四个字符,那后面的读到了文件末尾,返回EOF,值为-1;

进一步改良:

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_1.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	int c;
	while (~(c = fgetc(pt)))//while ((c = fgetc(pt)) != EOF)
	{
		printf("%d %c\n", c, c);
	}
	fclose(pt);
	pt = NULL;

	return 0;
}

 2.fputc

fputc - C++ Reference (cplusplus.com)

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_2.txt", "w");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputc('a', pt);
	fputc('b', pt);
	fputc('c', pt);
	fclose(pt);
	pt = NULL;

	return 0;
}

 

 需要注意的是,如果该程序多次执行,并且是文件都是同一个,那么下一次写入文件的内容会覆盖上一次写入文件的内容。

在一次程序执行中,由于将字符写进流中同时会推进光标,那么就可以向文件输出26个大写字母:

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_2.txt", "w");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	for (int i = 0; i < 26; i++)
	{
		fputc('a' + i, pt);
	}

	fclose(pt);
	pt = NULL;

	return 0;
}

 

 3.fgets

fgets - C++ Reference (cplusplus.com)

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_3.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	char s[100];
	fgets(s, 20, pt);
	if (s != NULL)
	{
		puts(s);
	}
	fclose(pt);
	pt = NULL;

	return 0;
}

 

 

 为什么最后不是t呢?因为fgets的第二个参数指定了读入多少个字符,其中最后一位是要留给'\0'的,所以第20位是'\0'。那么要想26个全部读入,就需要指定读入26+1位。

与上面相同的代码,把文件内容改成:

结果是:

  

 需要注意的是,读取文件时读到(num-1)个字符时(遇到'\0')或者换行符或者文件末尾时会结束读取。

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_3.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	char s[100];
	char* str = fgets(s, 20, pt);
	if (str != NULL)
	{
		puts(str);
	}
	fgets(s, 20, pt);
	if (s != NULL)
	{
		puts(s);
	}

	fclose(pt);
	pt = NULL;
	str = NULL;

	return 0;
}

 

 

 fgets返回值就是s字符数组的指针,所以这里的str就是s。

 puts也会自动添加'\n'。

4.fputs

fputs - C++ Reference (cplusplus.com)

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_3.txt", "r");
	if (pt == NULL)
	{
		perror("fopen_project_3.txt");
		return 1;
	}
	char s[100];
	fgets(s, 27, pt);
	fclose(pt);
	pt = NULL;

	FILE* str = fopen("project_4.txt", "w");
	if (str == NULL)
	{
		perror("fopen_project_4.txt");
		return 1;
	}
	fputs(s, str);
	fclose(str);
	str = NULL;

	return 0;
}

 

 

 思路是将读取到的信息再写到另一个文件中。

需要注意的是在写入流时遇到'\0'会停止写入,而且字符串末尾的'\0'并不会写进流中:

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_4.txt", "w");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	char s[100] = { 'a','b','c','d','\0','e','f','g','h','i','\0'};
	fputs(s, pt);
	fputs(s, pt);

	fclose(pt);
	pt = NULL;
	return 0;
}

 

 这就说明了fputs函数在写进流的过程并不会同时推进光标移动。

也可以在标准流中操作:

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_4.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	char arr[20] = "xxxxxxxxxxxxx";
	fgets(arr, 10, stdin);
	fputs(arr, stdout);

	fclose(pt);
	pt = NULL;

	return 0;
}

 

5.fscanf

fscanf - C++ Reference (cplusplus.com)

(内容有点多,可以点链接进去看看)

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_4.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	int a, b;
	char s[100];
	fscanf(pt, "%d %d %s", &a, &b,s);
	printf("%d %d %s\n", a, b,s);
	fclose(pt);
	pt = NULL;

	return 0;
}

 

 可以这么理解:

6.fprintf

fprintf - C++ Reference (cplusplus.com)

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_4.txt", "w");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	int a = 18;
	char c = 'c';
	char s[100] = "qwer";
	fprintf(pt, "%d\n%c %s", a, c, s);
	fclose(pt);
	pt = NULL;

	return 0;
}

 

 也可以这么理解:

7.fread

fread - C++ Reference (cplusplus.com)

简单的说:

ptr:指向存储读取数据的内存块的指针

size:每个数据项的大小(以字节为单位)

count:要读取的数据项的数量

stream:指向FILE对象的指针,它指向要读取数据的文件

fread函数从指定的文件流中读取数据,并将其存储在ptr指向的内存块中。它返回实际读取的数据项的数量,如果出现错误或文件结束,则返回值可能小于count。

fread通常用于读取二进制文件中的数据,例如图像、音频或视频文件。它可以读取任意类型的数据,因为它以字节为单位进行读取,并且可以根据需要将其转换为其他数据类型。

#include <stdio.h>

int main()
{
	FILE* pt = fopen("project_3.txt", "rb");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	int arr[3] = { 0 };
	int count = fread(arr, sizeof(arr[0]), 3, pt);
	for (int i = 0; i < 3; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\ncount:%d", count);
	fclose(pt);
	pt = NULL;

	return 0;
}

 

 

8.fwrite

fwrite - C++ Reference (cplusplus.com)

 简单的说:

ptr:指向要写入数据的指针

size:每个数据项的大小(以字节为单位)

count:要写入的数据项的数量

stream:指向FILE对象的指针,表示要写入的文件 

该函数返回成功写入的数据项数量,如果返回值与count不相等,则可能表示写入失败。

#include <stdio.h>

int main()
{
	FILE* pt = fopen("pro_1.txt", "wb");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	int arr[10] = { 1,3,4,5,2,9,10,8,7,6 };
	fwrite(arr, sizeof(int), sizeof(arr) / sizeof(arr[0]), pt);

	fclose(pt);
	pt = NULL;

	return 0;
}

 

由于fwrite是以二进制形式写入的,所以以文本形式去打开是我们看不懂的乱码,我们试试以二进制形式打开看看:

 9.scanf/fscanf/sscanf/printf/fprintf/sprintf函数的对比

scanf--标准输入流的格式化(即指定格式)函数

printf--标准输出流的格式化函数

fscanf--所有流输入的格式化函数

fprintf--所有流输出的格式化函数

sscanf--从字符串中读取格式化数据,并返回读取成功的个数

sscanf - C++ Reference (cplusplus.com)

 

#include <stdio.h>

int main()
{
	const char s[] = "I am not a pig";
	char s1[10], s2[10], s3[10], s4[10],s5[10];
	int a  = sscanf(s, "%s %s %s %s %s", s1, s2, s3, s4,s5);
	printf("%s %s %s %s\n%d", s1, s2, s4, s5,a);

	return 0;
}

 

 sprintf--把格式化数据转化为一个字符串

sprintf - C++ Reference (cplusplus.com)

#include <stdio.h>

int main()
{
	char s[100];
	sprintf(s, "%s", "I am not a pig");
	puts(s);

	return 0;
}

 

6.文件的随机读写

前面讲文件的顺序读写,进行读写都是从文件的开头开始的,那如果要从文件的某一位置开始读写,就要用到相应函数实现文件的随机读写(随机读写并非无任何规律地读写,而是指文件读写时的起始位置可以指定)

1.fseek

fseek - C++ Reference (cplusplus.com)

作用:根据文件指针(也可以理解是光标)的位置和偏移量来定位文件指针,fseek 允许在读取和写入之间切换。

返回值:如果定位成功就返回0;如果定位失败就返回-1

 stream:指向标识流的 FILE 对象的指针

offset:偏移量,即为要移动的字节数

origin:表示偏移量的基准位置,可以是以下之一:

SEEK_SET:从文件开始位置开始偏移。
SEEK_CUR:从当前位置开始偏移。
SEEK_END:从文件末尾开始偏移。

 注意:使用fseek函数进行文件定位时,需要确保文件以二进制模式打开,否则可能会出现意外的结果。

#include <stdio.h>

int main()
{
	FILE* pt = fopen("pro_1.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	char c = fgetc(pt);
	printf("%c\n", c);
	c = fgetc(pt);
	printf("%c\n", c);
	c = fgetc(pt);
	printf("%c\n", c);
	if (fseek(pt, -1, SEEK_CUR))//在定位之前,指向的是d,在此位置-1向前偏移一位指向c
	{
		printf("定位失败\n");
		return 1;
	}
	c = fgetc(pt);
	printf("%c\n", c);
	if (fseek(pt, -1, SEEK_END))//在末尾位置-1向前偏移一位指向z
	{
		printf("定位失败\n");
		return 1;
	}
	c = fgetc(pt);
	printf("%c\n", c);
	if (fseek(pt, 25, SEEK_SET))//在文件开头25向后偏移25位指向z
	{
		printf("定位失败\n");
		return 1;
	}
	c = fgetc(pt);
	printf("%c\n", c);
	if (fseek(pt, 0, SEEK_SET))//文件开头位置偏移0位
	{
		printf("定位失败\n");
		return 1;
	}
	c = fgetc(pt);
	printf("%c\n", c);

	fclose(pt);
	pt = NULL;

	return 0;
}

 

 

2.ftell

ftell - C++ Reference (cplusplus.com)

作用:返回文件(二进制文件和文本文件都可以)指针相对于起始位置的偏移量;如果发生错误,返回-1

#include <stdio.h>

int main()
{
	FILE* pt = fopen("pro_1.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	fgetc(pt);
	fgetc(pt);
	fgetc(pt);
	fgetc(pt);
	if (fseek(pt, 4, SEEK_CUR))
	{
		perror("fseek");
		return 1;
	}
	long int a = ftell(pt);
	printf("%ld\n", a);//4+4=8

	fclose(pt);
	pt = NULL;

	return 0;
}

 

3.rewind

rewind - C++ Reference (cplusplus.com)

作用:将文件指针重新指向文件开头

无返回值

#include <stdio.h>

int main()
{
	FILE* pt = fopen("pro_1.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	if (fseek(pt, 25, SEEK_SET))
	{
		perror("fseek");
	}
	printf("%ld\n", ftell(pt));
	rewind(pt);
	printf("%ld\n", ftell(pt));
	fclose(pt);
	pt = NULL;

	return 0;
}

 

7.文件读取结束的判断

文件读取结束一般为两种情况:1,文件读取遇到文件末尾结束;2,文件读取失败而结束。

首先,如何判断文件读取结束了呢?

1.对于读取文本文件,我们用fgetc和fgets函数读取;当读取失败时或者遇到文件末尾时而结束读取,fgetc都是返回EOF,fgets都是返回NULL,但此时不知道是因为读到文件末尾还是读取过程中失败而结束。

2.对于读取二进制文件,我们用fread函数读取;由于fread函数可以指定读取的个数,返回值为实际读取到的个数,所以我们可以根据fread的返回值来判断:

当返回值等于指定个数,表示文件读取结束并且读到了文件末尾;

当返回值小于指定个数,表示文件读取结束,但此时也不知道是因为读到文件末尾还是读取过程中失败而结束。

所以我们需要这两个函数来判断结束的原因:

1.feof

feof - C++ Reference (cplusplus.com)

作用:判断读取结束的原因是否是遇到文件末尾结束。

返回值:feof的返回值是一个整数,如果文件指针已经到达了文件末尾,则feof返回非零值;否则返回0。

2.ferror

ferror - C++ Reference (cplusplus.com)

作用:判断读取结束原因是否是读取失败结束。

返回值:ferror的返回值是一个整数,如果文件发生错误读取失败,则ferror返回非零值;否则返回0。

//文本文件

#include <stdio.h>

int main()
{
	FILE* pt = fopen("1.txt", "r");
	if (pt == NULL)
	{
		perror("fopen");
		return 1;
	}
	int a;
	while ((a = fgetc(pt)) != EOF)
	{
		printf("%c", a);
	}
	printf("\n");
	if (feof(pt))
	{
		printf("读到了文件末尾\n");
	}
	else if (ferror(pt))
	{
		printf("读取错误\n");
	}

	fclose(pt);
	pt = NULL;

	return 0;
}
//二进制文件

#include <stdio.h>
#include <string.h>

int main()
{
	FILE* pt = fopen("2.txt", "wb");
	if (pt == NULL)
	{
		perror("fopen_wb");
		return 1;
	}
	const char s[100] = "Hello World";
	fwrite(s, sizeof(s[0]), strlen(s), pt);
	fclose(pt);

	pt = fopen("2.txt", "rb");
	if (pt == NULL)
	{
		perror("fopen_rb");
		return 1;
	}
	char s1[100];
	size_t count = fread(s1, sizeof(s[0]), strlen(s), pt);
	s1[strlen(s)] = '\0';
	
	if (count == strlen(s))
	{
		printf("读取结束,并且全部读取:%s",s1);
	}
	else
	{
		if (feof(pt))
		{
			printf("读取到文件末尾\n");
		}
		else if (ferror(pt))
		{
			printf("读取错误\n");
		}
	}

	fclose(pt);
	pt = NULL;

	return 0;
}

8.文件缓冲区

1.文件缓冲区?

文件缓冲区是计算机内存中的一块区域,用于临时存储文件的数据。当程序读取或写入文件时,数据通常首先被存储在文件缓冲区中,然后再被写入到磁盘或从磁盘读取。文件缓冲区的存在可以显著提高文件读写的效率。因为磁盘的读写速度通常比内存慢得多,所以将数据先存储在内存中再一次性地全部输入输出,可以减少对磁盘的访问次数,从而加快文件的读写操作。另外,文件缓冲区还可以减少对磁盘的磨损,因为频繁的读写操作可能会导致磁盘的损坏。通过将数据先存储在内存中,可以减少对磁盘的访问次数,从而延长磁盘的使用寿命。总的来说,文件缓冲区在文件读写过程中起着非常重要的作用,它可以提高文件读写的效率,减少对磁盘的访问次数,同时还可以减少磁盘的磨损。

2.缓冲区与流的关系

缓冲区和流之间有密切的关系,流是数据在程序之间传输的通道,而缓冲区则是用来临时存储数据的区域。在数据通过流进行传输的过程中,缓冲区可以帮助提高数据传输的效率,减少频繁的读写操作,从而提高程序的性能。

3.完全缓冲

流缓冲是指在数据传输过程中,将数据暂时存储在缓冲区中,以便在合适的时机进行处理或传输。流缓冲可以提高数据传输的效率和稳定性,避免数据丢失或传输中断。在计算机编程中,流缓冲常常用于输入输出流的处理,例如在读取文件或网络数据时进行缓冲处理,以提高读取和写入的效率。

完全缓冲是指将数据完全存储在缓冲区中,直到缓冲区被填满或者手动进行刷新操作。在完全缓冲模式下,数据不会立即被写入到输出设备,而是先存储在缓冲区中,等到缓冲区满了之后再一次性写入输出设备,这样可以减少I/O操作的次数,提高效率。完全缓冲通常用于文件操作,例如在C语言中,使用标准I/O库中的函数进行文件读写时,默认是完全缓冲模式。

I/O库是指输入/输出库,它是计算机编程中用于处理输入和输出操作的软件库。I/O库提供了一系列的函数和类,用于读取和写入文件、处理网络数据、控制设备等操作。通过I/O库,程序可以与外部设备进行交互,进行数据的输入和输出操作。

在不同的编程语言中,都有对应的I/O库,例如在C语言中,可以使用标准I/O库(stdio.h)来进行文件的读写操作;在Java中,可以使用Java I/O库进行文件、网络等操作;在Python中,可以使用内置的I/O库进行文件读写等操作。I/O库是编程中非常重要的一部分,它提供了丰富的功能和接口,帮助程序实现与外部环境的数据交换和通信。

4.缓冲区刷新(fflush)

C语言中使用标准I/O库的函数进行文件读写,默认为完全缓冲;在使用fclose关闭文件时,同时会刷新缓冲区,如果中途需要刷新缓冲区,可以使用fflush函数手动刷新缓冲区:

fflush - C++ Reference (cplusplus.com)

以上就是文件操作的全部内容,如果对你有帮助那就点个赞收个藏呗;如果文章存在错误或者需要补充的地方 ,欢迎评论区指讨论.^o^.

  • 26
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值