C语言重点难点精讲C语言文件

Posted 我擦了DJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言重点难点精讲C语言文件相关的知识,希望对你有一定的参考价值。

一:文件相关概念

(1)什么是文件

我们在磁盘上所见到的都是文件,在程序设计中,所谈到文件主要有两种:

  • 一种是程序文件:包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe);
  • 另一种是数据文件:文件的内容不一定是程序,也可以是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件

本节主要讨论的是数据文件

(2)文件名

一个文件有“文件路径+文件主干+文件后缀”三部分组成,为了方便起见,文件表示也被称为文件名

(3)文件类型

数据文件可以被分为文本文件二进制文件

  • 举个例子,程序里有个变量是10000,如果要把它放到磁盘里,你想要让用户读懂那么你肯定要用字符表示,也就是1对应的ASCII码,2对应的ASCII码,这样去转换,那么这种就是文本。如果不经过任何转换,就是二进制文件(使用记事本方式打开exe文件时的乱码)

如下程序代码表示将数字10000用存储为二进制文件

int main()
{
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	fwrite(&a, 4, 1, pf)//二进制写
	fclose(pf);
	pf = NULL;
	return 0;
}

虽然显示的是txt文件,但是其本质是二进制文件,所以用记事本打开是乱码

要去看到到底是什么,可以用VS,使用二进制编辑器打开

二:文件指针

每一个使用的文件,在内存中都会开辟一个文件信息区,这个文件信息区存放的是文件的名字,文件的状态等等,所有的这些信息存放在一个结构体变量中,将其取名为FILE

既然它是结构体变量,那么我们就可以创建一个指针去操作它,这个指针也就被称为文件指针

FILE* pf;//文件指针

pf是一个指向FILE类型的数据变量,可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就可以访问该文件

三:文件的打开和关闭

文件读写时先打开文件,再关闭文件
在打开文件的时候,会返回一个File*的指针,C语言规定使用fopen打开文件,fclose关闭文件

FILE* fopen(const char* filename,const char* mode);
int fclose(FILE* stream)

mode选项有如下几种

int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL) {
	printf("%s\\n", strerror(errno));
	return 0;
}
fclose(pf);
pf == NULL;
return 0;
}

四:文件的顺序读写

读写函数如下

注意标准输入流和标准输入流

int main()
{
	char arr[1024] = { 0 };
	fgets(arr, 1024, stdin);//键盘就是标准输入流
	fputs(arr, stdout);//屏幕是标准输出流
}

注意这几组函数

  • scanfprintf是针对标准输入/输出流的格式化输入/输出语句
  • fscanffprintf是针对所有输入/输出流的格式化输入/输出语句
  • sscanf是从字符串中读取格式化的数据
  • sprintf是把格式化数据输出到字符串

(1)写

1:字符输出

int main()
{
	FILE* pfwrite = fopen("test.txt", "w");
	if (pfwrite == NULL) {
		printf("%s\\n", strerror(errno);
		return	0;
	}
	fputc('L', pfwrite);
	fputc('o', pfwrite);
	fputc('v', pfwrite);
	fputc('E', pfwrite);
	fclose(pfwrite);
	pfwrite = NULL;
	return 0;
}

2:文本行输出,其中换行需要手动加入

int main()
{
	FILE* pfwrite = fopen("test.txt", "w");
	if (pfwrite == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	fputs("I\\n", pfwrite);
	fputs("LOVE\\n", pfwrite);
	fputs("YOU", pfwrite);
	return 0;
}

3:格式化输出

struct S
{
	int n;
	float score;
	char arr[10];
};

int main()
{
	struct S s = { 100,3.14f,"love" };
	FILE* pfwrite = fopen("test.txt", "w");
	if (pfwrite == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	fprintf(pfwrite, "%d-%f-%s", s.n, s.score, s.arr);//格式化输出
	return 0;
}

4:二进制输出

struct S
{
	char arr[10];
	int age;
};

int main()
{
	struct S s = { "Bob",19};
	FILE* pfwrite = fopen("test.txt", "wb");//二进制
	if (pfwrite == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	fwrite(&s, sizeof(struct S), 1, pfwrite);
	return 0;
}

(2)读

1:字符读入

int main()
{
	FILE* pfread = fopen("test.txt", "r");
	if (pfread == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	printf("%c", fgetc(pfread));
	printf("%c", fgetc(pfread));
	printf("%c", fgetc(pfread));
	printf("%c", fgetc(pfread));
	printf("%c", fgetc(pfread));
	return 0;
}

2:文本行输入,可以获得换行符

int main()
{
	FILE* pfread = fopen("test.txt", "r");
	if (pfread == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	char a[20];
	fgets(a, 6, pfread);//读一行6个字符
	printf("%s\\n", a);
	return 0;
}

3:格式化输入

struct S
{
	int n;
	float score;
	char arr[10];
};

int main()
{
	struct S s = { 0 };
	FILE* pfread = fopen("test.txt", "r");
	if (pfread == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	fscanf(pfread, "%d%f%s", &(s.n), &(s.score), &(s.arr));
	printf("%d-%f-%s", s.n, s.score, s.arr);
	return 0;
}

4:二进制输入


int main()
{
	struct S s = { 0 };
	FILE* pfread = fopen("test.txt", "rb");//二进制
	if (pfread == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	fread(&s, sizeof(struct S), 1, pfread);
	printf("%d-%f-%s", s.n, s.score, s.arr);
	return 0;
}

五:文件的随机读取

(1)fseek

文件指针开始会指向文件内容的开头,顺序读取时想要读取某个特定字符时,必须先读其前面的字符,而使用随机读取,可以直接偏移文件指针,直接读取
需要注意,在读取完成后文件指针会自动向后偏移

  • SEEL_CUR:以文件指针的当前位置偏移
  • SEEK_END:以文件的末尾位置偏移
  • SEEK_SET:以文件的起始位置开始
int main()
{

	FILE* pfread = fopen("test.txt", "r");
	if (pfread == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	fseek(pfread, 2, SEEK_CUR);//以当前位置偏移整数
	printf("%c\\n", fgetc(pfread));
	return 0;
}

(2)ftell

返回当前文件指针相对于起始位置的偏移量

int main()
{

	FILE* pfread = fopen("test.txt", "r");
	if (pfread == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	fgetc(pfread);//读取一个跳过一个
	int pos = ftell(pfread);
	printf("%d\\n", pos);
	
	fclose(fread);
	return 0;
}

(3)rewind

让文件指针回到起始位置

int main()
{

	FILE* pfread = fopen("test.txt", "r");
	if (pfread == NULL) {
		printf("%s\\n", strerror(errno));
		return	0;
	}
	fgetc(pfread);//读取一个跳过一个
	int pos1 = ftell(pfread);
	rewind(pfread);//回到其实位置
	int pos2 = ftell(pfread);
	printf("%d\\n", pos2);//结果仍然是0
	
	fclose(fread);
	return 0;
}

六:文件结束条件判定

对于fgetc,如果其返回值为EOF;对于fgets,如果其返回值为NULL,就代表文件读到末尾
需要特别注意的一点是千万不要用feof判断文件结束

下面是读到文件末尾的标准写法

while ((c = fgetc(fp)) != EOF)
{
	//操作
}

以上是关于C语言重点难点精讲C语言文件的主要内容,如果未能解决你的问题,请参考以下文章

C语言重点难点精讲C语言指针

C语言重点难点精讲C语言预处理

C语言重点难点精讲C语言内存管理

C语言重点难点精讲C语言中的重要符号

C语言重点难点精讲第一部分关键字:第一节-关键字分类细讲

漫谈C语言重点难点