C语言文件操作(上)

一.对文件的初步了解

1.使用文件的意义:将数据直接存放在电脑的硬盘上,做到了数据的持久化。
2.文件分为程序文件(包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe))和数据文件(文件的内容不一定是程序,而是程序运行时读写的数据)。
3.文件名包含3部分:文件路径+文件名主干+文件后缀。一个路径下只能不能有相同的文件名,否则无法起到标识作用。
例如: c:\code\test.txt(c:\code\为文件路径;test为文件名主干;.txt为文件后缀)

二.文件指针

1.文件指针类型

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息,这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE。文件指针本质上是结构体指针。
例如,VS2013编译环境下的FILE:

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

2.文件指针

FILE* pf;//文件指针变量

pf是文件指针变量,指向一个结构体,该结构体中存放了一个文件的多个信息,可以通过指针pf来访问、管理该文件。如图:
C语言文件操作(上)_第1张图片

三.文件的打开与关闭

1.打开、关闭文件函数

(1)打开文件函数:fopen

C语言文件操作(上)_第2张图片

在这里插入图片描述

返回值:文件指针类型,成功打开文件就返回该文件的地址,打开失败就返回NULL。
参数一:被打开文件的文件名,即文件指针。相对路径和绝对路径下的文件名写法不同。
参数二:打开模式,即打开这个文件要用来进行什么操作。模式有下图的几种
C语言文件操作(上)_第3张图片

相对路径和绝对路径下文件名(文件指针)的写法:

1.相对路径:
把文件创建在当前程序(正在编译)路径下时,直接写文件名如"data.txt"即可:
在这里插入图片描述
C语言文件操作(上)_第4张图片
2.绝对路径
①把程序创建在桌面上,需要在原文件名前加上桌面的路径,还要在每个’““前加上一条””,以防被当做转义字符
C语言文件操作(上)_第5张图片

②在test.c文件的当下目录的debug文件下创建data.txt文件
一个".“代表当下目录,两个”.“代表上一级目录,依次类推。C语言文件操作(上)_第6张图片
创建完成:
C语言文件操作(上)_第7张图片
③在test.c文件的上一级目录的Debug文件下创建data.txt文件
此时需要两个”."
C语言文件操作(上)_第8张图片
创建成功:
C语言文件操作(上)_第9张图片
注:以.txt结尾的文件名是显示文件扩展名后的.txt,在创建文件命名时要注意有没有勾上文件扩展名这一选项
C语言文件操作(上)_第10张图片

(2)关闭文件函数:fclose

int fclose ( FILE * stream );

C语言文件操作(上)_第11张图片

返回值:整型
参数:文件指针pf,即流

2.对于流的理解

☀️流(自定义名字,可以是pf也可以是别的)的写法:

FILE* pf = fopen("data.txt", "r");

pf就是例子中被创建的流。自定义名字,可以是pf也可以是别的。
☀️“流”是程序与运行环境(系统)间互动的通风。当我们需要程序与系统间进行互动,例如读取和写入,我们就需要建立一个“流”。fopen( )函数就创建了一个流,它返回的指针成为我们在流里执行具体操作的工具;fclose就关闭了这个流。
☀️写程序时,除键盘输入外还有多种输入方式,比如打印机、摄像头,同样的也有很多种输出方式,要输出到各种各样不同的外部设备上去。这样的话就需要程序员懂各种各样的外部设备的读写方式。但如果先把文件转换成统一的一种格式(流),再将统一的流交给不同专业人员转换成不同的输入输出模式,就大大降低难度,程序员只用关心如何转换成流,至于如何让流于外部设备交互不用关心。
☀️为什么我们之前用printf和scanf时不需要文件指针也不知道流的概念?
答:看似我们使用printf函数和scanf函数时不用打开任何文件,其实已将默认打开了3个流,即使用了三个文件指针。
在这里插入图片描述

3.文件的打开与关闭固定模版

关于文件的打开与关闭,有一个相对固定的模版。

int main()
{
    //打开文件,并判断是否打开成功
    FILE* pFile = fopen("myfile.txt", "r/...");
                        //r的位置是模式,有多种模式
    if (pFile == NULL)
    {
        perror("fopen");
        return 1;
    }

    //文件操作
    //各种操作···
    //文件操作
    
    //关闭文件,将流置为空指针
    fclose(pFile);
    pFile = NULL;
    return 0;
}

①创建FILE ∗ * 类型的变量pFILE:FILE ∗ * pFile;
②与打开文件函数进行连接:pFile = fopen ( );
③在fopen函数中写文件名和要对文件进行的操作,如:fopen (“myfile.txt”,“w”);
④如果pFILE接收到的是NULL,说明打开文件失败,提示错误信息后关闭文件
⑤对文件进行操作
⑥关闭文件并将文件指针pFILE置为NULL

四.文件的顺序读写函数对应模式

当在FILE ∗ * fopen ( const char ∗ * filename, const char ∗ * mode );函数中选择了文件名filename和模式mode后,就意味着接下来文件操作部分只能使用对应于mode的文件操作函数
C语言文件操作(上)_第12张图片

五.文件的顺序读写函数

1."w"模式下适用于所有输出流的函数

☀️(1)fputc:给文件内写进一个字符

C语言文件操作(上)_第13张图片
①对于fputc函数,没有pf要求打开的文件的话则自动创建文件
②第一个参数是int类型的字符,即把字符转换成ASCII码值的形式传给函数
③用一次fputc函数就写一个字符,不提示换行就接着上一个元素的右边往右写
④如果不想把内容写到文件中,想写到控制台显示器上,则将"pf"部分改成"stdout",即改成标准输出流
⑤返回值:成功写入文件则返回写进去的这个字符;调用失败或文件读取结束,函数返回“EOF”
练习1:打印字符’a’、‘b’、'c’到指定文件中

int main()
{
	//打开文件并对文件名进行空指针判断
	//如果是空指针说明打开文件失败
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	//关文件并将文件名指针置为空
	fclose(pf);
	pf = NULL;
	return 0;
}

查看文件data内部:
C语言文件操作(上)_第14张图片
练习2:打印26个小写字母到指定文件中

int main()
{
	//打开文件并对文件名进行空指针判断
	//如果是空指针说明打开文件失败
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	int i = 0;
	for (i = 0;i < 26;i++)
	{
		fputc('a' + i, pf);
	}
	//关文件并将文件名指针置为空
	fclose(pf);
	pf = NULL;
	return 0;
}

查看文件data内部:
C语言文件操作(上)_第15张图片
练习3:用fputc函数将内容写到控制台显示器上(只用把pf改成stdout),顺便看一下换行的情况

//写文件
	int i = 0;
	for (i = 0;i < 26;i++)
	{
		if (i == 10)
		{
			printf("k\n");
			continue;
		}
		fputc('a' + i, stdout);
	}

控制台显示结果:
C语言文件操作(上)_第16张图片

☀️(2)fputs:给文件内写进一串字符串

C语言文件操作(上)_第17张图片
①只负责写,不换行,要换行的话加’\n’
②参数一:const char ∗ * str;直接写字符串的内容,但编译器存的实际上是这串字符串的首元素地址
③返回值:成功写入文件则返回一个非负值;调用失败或文件读取结束,函数返回“EOF”
练习1:

int main()
{
	//打开文件并对文件名进行空指针判断
	//如果是空指针说明打开文件失败
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fputs("hello bit", pf);
	fputs("hello xiaobite", pf);
	
	//关文件并将文件名指针置为空
	fclose(pf);
	pf = NULL;
	return 0;
}

查看data文件内部:
C语言文件操作(上)_第18张图片
练习2:不想写进data.txt文件内,想打印到控制台显示器上(只用把pf改成stdout)

//写文件
	fputs("hello bit\n", stdout );
	fputs("hello xiaobite", stdout);
	

控制台显示结果:
C语言文件操作(上)_第19张图片

☀️(3) fprintf:将各种类型数据按格式写入文件

在这里插入图片描述
C语言文件操作(上)_第20张图片
返回值:写入成功,返回写入文件的字符的个数

练习:按格式将数据写入文件,并得到fprintf函数此时的返回值

struct S
{
	int a;
	float s;
};
int main()
{
	//打开文件并对文件名进行空指针判断
	//如果是空指针说明打开文件失败
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	struct S s = { 100,3.14f };
	int num= fprintf(pf, "%d %f", s.a, s.s);
	printf("%d", num);

	//关文件并将文件名指针置为空
	fclose(pf);
	pf = NULL;
	return 0;
}

查看data文件内部:
C语言文件操作(上)_第21张图片
控制台显示的返回值;
C语言文件操作(上)_第22张图片
返回值是12,证明了返回值是输入的字符(包括空格和标点符号)的个数

☀️(4)对比printf、fprintf、sprintf

C语言文件操作(上)_第23张图片
sprintf函数:
C语言文件操作(上)_第24张图片
功能:把一组格式化数据转换成字符串形式
返回值:函数调用成功,返回存入字符串的字符个数;调用失败,返回一个负数
练习:将一组格式化数据以字符串形式打印出来,并得到sprintf此时的返回值

struct S
{
	int a;
	float s;
	char str[10];
};
int main()
{
	char arr[30] = { 0 };
	struct S s = { 100,3.14f,"bit" };
	int num=sprintf(arr, "%d %f %s", s.a, s.s, s.str);
	printf("%s\n", arr);
	printf("%d", num);
	return 0;
}

控制台显示结果:
C语言文件操作(上)_第25张图片
sprintf的返回值是16,就是字符串arr的元素个数

C语言文件操作(上)_第26张图片

2."r"模式下适用于所有输入流的函数

☀️(1)fgetc:从文件内读出一个字符

C语言文件操作(上)_第27张图片
①对于fgetc函数,只有指定文件以及被我们创建好的情况下才能进一步读取文件中数据,当没有指定文件时,不会自动创建文件
②如果不想从文件中读,想从键盘上读,只需把pf改成stdin
③返回值:成功从文件读出则返回读到的这个字符;调用失败或文件读取结束,函数返回“EOF”
练习1:data.txt文件中放了abc三个字母,一次读一个字母,将三个字母读出来
创建data.txt文件并在文件中写abc:
C语言文件操作(上)_第28张图片

int main()
{
	//打开文件并对文件名进行空指针判断
	//如果是空指针说明打开文件失败
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int i = 0;
	for (i = 0;i < 3;i++)
	{
		printf("%c\n", fgetc(pf));
	}
	//关文件并将文件名指针置为空
	fclose(pf);
	pf = NULL;
	return 0;
}

控制台显示结果:
C语言文件操作(上)_第29张图片
练习2:不想从文件中读,想从键盘上读3个字母(只需把pf改成stdin)

int i = 0;
	for (i = 0;i < 3;i++)
	{
		//int ch= fgetc(pf);
		printf("%c\n", fgetc(stdin));
	}

控制台显示结果:
C语言文件操作(上)_第30张图片

☀️(2)fgets:从文件内读出一串字符串

C语言文件操作(上)_第31张图片
①fgets可以一次读一行内指定个数的元素
②参数num为n时实际读到的只有n-1个,第n个放的是’\n’
③当一行内有的元素不够指定个数num时,有多少读多少,不会接着读下一行的
④一个程序内读完一次就进行偏移,下一次读的不会是上一次读到的
③返回值:成功读到内容,则返回一个读到的字符串的首元素地址;调用失败或文件读取结束,函数返回NULL
练习1:一次一行地读文件中的内容

int main()
{
	//打开文件并对文件名进行空指针判断
	//如果是空指针说明打开文件失败
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	char arr[10] = { 0 };
	fgets(arr, 10, pf);
	printf("%s\n", arr);
	fgets(arr, 10, pf);
	printf("%s", arr);
	
	//关文件并将文件名指针置为空
	fclose(pf);
	pf = NULL;
	return 0;
}

控制台显示结果:
C语言文件操作(上)_第32张图片
练习2:不想从文件中读,想从键盘上读一串字符串(只需把pf改成stdin)

int main()
{
	//打开文件并对文件名进行空指针判断
	//如果是空指针说明打开文件失败
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	char arr[10] = { 0 };
	fgets(arr, 10,stdin );
	printf("%s\n", arr);
	fgets(arr, 10, stdin);
	printf("%s\n", arr);
	
	//关文件并将文件名指针置为空
	fclose(pf);
	pf = NULL;
	return 0;
}

控制台显示结果:
C语言文件操作(上)_第33张图片

☀️(3)fscanf:从文件中将各种类型数据按格式读出

C语言文件操作(上)_第34张图片C语言文件操作(上)_第35张图片
返回值:读取成功,返回读取到的的字符的个数

练习:从data.txt文件中按格式读取数据
此时data.txt文件内有:

C语言文件操作(上)_第36张图片

struct S
{
	int a;
	float s;
};
int main()
{
	//打开文件并对文件名进行空指针判断
	//如果是空指针说明打开文件失败
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	struct S s = { 0 };
	fscanf(pf, "%d %f", &(s.a), &(s.s));
	printf("%d %f", s.a, s.s);
	
	//关文件并将文件名指针置为空
	fclose(pf);
	pf = NULL;
	return 0;
}

控制台显示结果:
C语言文件操作(上)_第37张图片

☀️(4)对比scanf、fscanf、sscanf

C语言文件操作(上)_第38张图片
sscanf函数:
C语言文件操作(上)_第39张图片
功能:将格式化字符串按格式拆解成多组数据
返回值:函数调用成功,返回存入字符串的字符个数;调用失败,返回EOF
练习:将一组格式化数据按格式拆解成多组数据并打印出来

struct S
{
	int a;
	float s;
	char str[10];
};
int main()
{
	char arr[30] = { 0 };
	struct S s = { 100,3.14f,"bit" };
	struct S tmp = { 0 };
	sprintf(arr, "%d %f %s", s.a, s.s, s.str);
	sscanf(arr, "%d %f %s", &(tmp.a), &(tmp.s), &(tmp.str));
	printf("%d %f %s", tmp.a, tmp.s, tmp.str);
	return 0;
}

控制台显示结果:
C语言文件操作(上)_第40张图片

3.二进制下输入输出函数

☀️(1)二进制模式

“wb”:二进制输出流;对应函数:fwrite
“rb”:二进制输入流 ;对应函数:fread

☀️(2)fwrite:二进制输出

C语言文件操作(上)_第41张图片
功能:将ptr指向空间中的count个大小为size的元素写入流中
返回值:成功写入则返回写进去的元素个数,即count;写入失败,返回0
练习:将数据二进制写入文件

struct S
{
	int a;
	float s;
	char str[10];
};
int main() 
{
	struct S s = { 99,12.3f,"bit" };
	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;
}

查看文件data内部:
C语言文件操作(上)_第42张图片
想要读懂二进制文件,也必须要用二进制的方式,可以通过fread读取被写进文件的数据。

☀️(3)fread:二进制输入

C语言文件操作(上)_第43张图片
①功能:将ptr指向的空间中的size大小的count个字符,以二进制形式存入流指向的函数
②返回值:成功读取则返回读到字符的个数,即count;若返回值小于count,则可能文件结尾或发生错误,通过ferror和feof判断具体哪种原因
练习:用fread,将通过fwrite写进data.txt的数据读出来

struct S
{
	int a;
	float s;
	char str[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.a, s.s,s.str);
	fclose(pf);
	pf = NULL;
	return 0;
}

控制台显示结果:
C语言文件操作(上)_第44张图片

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