C语言文件操作详解

文章目录

  • 以文本形式读和写
    • fgetc
    • fgets
    • fputc
    • fputs
    • fprintf
    • fscanf
    • sprintf 和 sscanf
  • 以二进制的形式读和写
    • fwrite
    • fread
  • 有关文件指针(文件中的光标)的函数
    • fseek
    • ftell
    • rewind

今天来讲一下如何通过C语言实现对于文件的读和写,它的应用场景可以是通讯录,我们每回存入的数据下一次运行的时候就会丢失,这是因为数据一直在内存中放着,并没有存入硬盘中, 通过文件操作,把数据存到文件中,就是存入到了硬盘中,下次用我们还能用到,总之,我们先循序渐进的讲吧,先来一个最简单的例子,我们来逐句剖析。

#include
int main() {
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//用于判断是否打开成功
	if (pf == NULL) {
		perror("fopen");//用于打印错误信息
		return 1;//直接停止程序
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

首先我们如何管理一个文件呢,我们在管理一个文件时会创建一个文件信息区,这个文件信息区会存放比如:文件名、文件大小、文件的位置等等,文件信息区本质上就是个结构体变量,该结构体的类型为FILE,是编译器设计之初就定义的一种专门用于存放文件信息的类型。在vs2013编译环境中FLIE的类型声明如下所示:

struct _iobuf 
{
	char* _ptr;
	int   _cnt;
	char* _base;
	int   _flag;
	int   _file;
	int   _charbuf;
	int   _bufsiz;
	char* _tmpfname;
};
typedef struct _iobuf FILE;

这就是我们为什么创建一个FILE*的指针,就是给要处理的文件在内存中开辟一个文件信息区去维护文件。
然后fopen是一个函数,第一个参数是要操作的文件名,第二个参数是要进行哪种操作,比如r是read,w是write,rb是以二进制的形式读,wb是以二进制的形式写。

‘r’:只读。该文件必须已存在。
‘r+’:可读可写。该文件必须已存在,写为追加在文件内容末尾。
‘rb’:表示以二进制方式读取文件。该文件必须已存在。
‘w’:只写。打开即默认创建一个新文件,如果文件已存在,则覆盖写(即文件内原始数据会被新写入的数据清空覆盖)。
‘w+’:写读。打开创建新文件并写入数据,如果文件已存在,则覆盖写。
‘wb’:表示以二进制写方式打开,只能写文件, 如果文件不存在,创建该文件;如果文件已存在,则覆盖写。
‘a’:追加写。若打开的是已有文件则直接对已有文件操作,若打开文件不存在则创建新文件,只能执行写(追加在后面),不能读。
‘a+’:追加读写。打开文件方式与写入方式和’a’一样,但是可以读。需注意的是你若刚用‘a+’打开一个文件,一般不能直接读取,因为此时光标已经是文件末尾,除非你把光标移动到初始位置或任意非末尾的位置。

需要注意的是,这两个参数都需要用双引号去引起来
下边的是用于判断是否打开成功,因为如果打开不成功的话,fopen
函数会返回空指针。也是有可能打印不成功的,因为如果没有这个文件的话,你还用“r”形式打开,那就会报错,但是用“w”的形式打开就不会,因为这样就是创建一个新的文件。
其实我们想一下也知道,你让程序去读文件中的内容,没有文件,那程序肯定不知道去哪里读,但是你让程序去写,没有就创建一个文件去写呗,这其实很好理解
然后下一步,就是要关闭文件了,这也是一个函数,最后要将文件指针置为空指针,要不然就成为野指针了。
以上是最基本的打开文件和关闭文件操作
当然了,还需要提一嘴,就是我们创建文件只能在当前目录(就是源文件所在的目录)下创建吗,当然不是了,我们之前写的data.txt这属于相对路径,当然我们也可以在双引号中写绝对路径,比如C:\Users\86193\Desktop\data.txt 这是我的电脑上在桌面上创建一个这样的文件的路径,每个文件都只有一个绝对路径,每一个绝对路径都只有一个文件。

int main() {
	FILE* pf = fopen("C:\\Users\\86193\\Desktop\\data.txt", "w");//需要转义一下
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	return 0;
}

当然我们用的时候需要将\转义一下。

int main() {
	FILE* pf = fopen(".\\Debug\\data.txt", "w");//当前目录下Debug文件夹下去创建
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	return 0;
}

当然相对路径还可以这么去操作,在前面加一个点表示在当前目录下的一个文件夹中去创建,找到上一级文件夹,就要加两个点。

FILE* pf = fopen("..\\test_9_24\\data.txt", "w");//上一级目录下test_9_24文件夹下去创建
FILE* pf = fopen("..\\..\\Common\\data.txt", "w");//上一级上一级

接下来我们说如何往文件中放东西

以文本形式读和写

fgetc

在这里插入图片描述
就是从文件中读取一个字符

int main() {
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	char ch = fgetc(pf);
	printf("%c", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

fgets

在这里插入图片描述
就是从文件中读取num-1个字符放到str中,因为有一个位置要放’\0’

int main() {
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	char arr[10] = { 0 };
	fgets(arr, 4, pf);
	printf("%s", arr);
	fclose(pf);
	pf = NULL;
	return 0;
}

所以这里会打印三个字符,需要注意的是,如果num大于一行的字符个数,那么把’\n’放到字符数组中之后再放个’\0’就不管了。下一回读的时候就从下一行开始读。
我们来试验一下:
C语言文件操作详解_第1张图片

fputc

在这里插入图片描述
就是把给定的字符放到文件中,如果之前的文件中有东西的话,结果相当于删掉之前的所有再写入一个字符,因为之前文件中的光标在文件的最开始。

int main() {
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	fputc('a', pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

fputs

在这里插入图片描述
就是把一个字符串放到文件当中,也是会覆盖掉之前的,原因与上面的一样

int main() {
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	fputs("abcdefg", pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

fprintf

在这里插入图片描述
在这里插入图片描述

就是以格式化的形式打印数据到文件中,它和printf只差一个文件指针,我们怎么用printf就怎么用fprintf就可以了,只需要最后在最前面加入一个文件指针就可以了。

struct S {
	int i;
	float f;
	char c[10];
};
int main() {
	struct S s = { 10,3.14f,"abcdef" };
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	fprintf(pf,"%d %f %s", s.i, s.f, s.c);
	fclose(pf);
	pf = NULL;
	return 0;
}

这样就把相关数据写到文件中了。

fscanf

在这里插入图片描述
在这里插入图片描述
它们之间的关系其实和上面那组的关系是一样的,这个是从文件中按格式化读取内容,把读到的放到后面,读的话要保证文件中有东西,没东西的话读出来的都是0

struct S {
	int i;
	float f;
	char c[10];
};
int main() {
	struct S s = { 0 };
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	fscanf(pf, "%d %f %s", &s.i, &s.f, s.c);
	printf("%d %f %s", s.i, s.f, s.c);
	fclose(pf);
	pf = NULL;
	return 0;
}

sprintf 和 sscanf

这两个函数其实和文件操作没什么关系,但谁让它们和前面的长得像呢,我们就来区分一下
在这里插入图片描述
这个是将后面格式化的数据写成一个字符串(输出到一个字符串中)
在这里插入图片描述
这个是从字符串中读取数据并把它们格式化(把字符串转化成对应的整形,浮点型等等)

struct S {
	int i;
	float f;
	char c[10];
};
int main() {
	struct S s = {10,3.14,"abcdef" };
	struct S s1 = { 0 };
	char arr[30] = { 0 };
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	sprintf(arr,"%d %f %s", s.i, s.f, s.c);
	printf("%s", arr);
	sscanf(arr,"%d %f %s", &s1.i, &s1.f, s1.c);
	printf("%d %f %s", s.i, s.f, s.c);
	fclose(pf);
	pf = NULL;
	return 0;
}

这就是它们的基本使用

以二进制的形式读和写

fwrite

在这里插入图片描述
第一个参数是一个地址,用来找到要写入的内容。第二个参数是要写入的每个元素的大小,第三个参数是要写入多少个元素

int main() {
	char arr[10] = "abcdef";
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	fwrite(arr, sizeof(char), 4, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}
struct S {
	int i;
	float f;
	char s[10];
};
int main() {
	struct S s = { 12,6.18,"abcdef" };
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	fwrite(&s, sizeof(struct S), 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

当然这时存进去的数据你是看不懂的,因为都是二进制数据。那我们用的时候就要用二进制的形式去读。

fread

在这里插入图片描述

struct S {
	int i;
	float f;
	char s[10];
};
int main() {
	struct S s = { 0 };
	FILE* pf = fopen("data.txt", "rb");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	fread(&s, sizeof(struct S), 1, pf);
	printf("%d %f %s", s.i, s.f, s.s);
	fclose(pf);
	pf = NULL;
	return 0;
}

这样就可以读出二进制数据并打印出来了。

有关文件指针(文件中的光标)的函数

fseek

在这里插入图片描述
C语言文件操作详解_第2张图片
这个函数是定位文件指针(光标),就是将光标放到你想要的位置,之前光标不是只能在开头嘛。第二个参数是偏移量,向左为负,向右为正,第三个参数是相对于哪个位置,分别是开头 目前 和最后。

ftell

在这里插入图片描述
它的作用是得到目前光标的位置,返回一个数。

rewind

在这里插入图片描述
它的作用是让光标回到起始位置

//文件中放的是abcdefg
int main() {
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	char ch = fgetc(pf);
	printf("%c\n",ch);
	ch = fgetc(pf);//每读取一个字符光标会向后移动一个位置
	printf("%c\n",ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	int ret = ftell(pf);//计算光标目前位置
	printf("%d\n", ret);
	fseek(pf, -2, SEEK_END);//把光标放到f位置
	ch = fgetc(pf);
	printf("%c\n", ch);
	rewind(pf);//把光标放到最开始的位置
	ch = fgetc(pf);
	printf("%c\n", ch);
	return 0;
}

C语言文件操作详解_第3张图片

你可能感兴趣的:(c语言,开发语言)