C语言文件操作

什么是文件

磁盘上的文件是文件。
但是在程序设计中,我们的文件一般有两种:程序文件、数据文件(从文件功能的角度分类的)。

程序文件

包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

之前了解的理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。
其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。

文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包括3部分:文件路径+文件名主干+文件后缀
例如:c:\code\test.c
为了方便起见,文件标识常被称为文件名

文件的打开和关闭

文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名
字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统
声明的,取名FILE.
例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

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

不同的C编译器的FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
下面我们可以创建一个FILE*的指针变量:

FILE*pf//文件指针变量

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过文件信息区中的信息就能访问该文件。而就是说通过文件指针变量就可能够找到与他关联的文件。
比如:在这里插入图片描述

文件的打开和关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件
在编写程序的时候,在打开文件的同时,都会返回一个FILE*指针变量指向该文件,也相当于建立的指针和文件的关系。
ANSIC规定使用fopen打开文件,使用fclose关闭文件

fopen和fclose

//打开文件
FILE*fopen(const char* filename, const char*mode);
//关闭文件
int fclose(FILE*stream);

文件的打开方式:
在这里插入图片描述
注意:打开方式中的“w”打开文件时会将原来文件中的内容覆盖掉。

举个例子:

#include<stdio.h>
int main()
{
	
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	//文件操作
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	else
	{
		printf("打开成功\n");
	}
	//读文件
	//....

	//关闭文件
	fclose(pf);
	pf = NULL;//置为空指针NULL,防止野指针

	return 0;
}

文件的顺序读写

在这里插入图片描述

可能看了这个表有一些疑惑?为啥fgetc是读取而不是写入,而fputc是写入不是读取。
因为这些函数的命名是站在内存的角度取命名,而写入读取是站在其他角度来看的(比如文件)。详解看下图:

在这里插入图片描述

fgetc函数(读)

函数原型:

int fgetc(FILE* stream);
  • 函数功能:从流中读取字符,即从stream所指定的文件中取得下一个字符。这里需要注意,在每取完一个字符时stream会自动向下移动一个字节。这样编成时,程序员就不用再stream控制了。这种功能在许多读写函数中都有体现。
  • 返回值:返回所得到的字符;若读入错误,返回EOF。
#include<stdio.h>
int main()
{

	//打开文件
	FILE* pf = fopen("test.txt", "r");
	//文件操作
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	else
	{
		printf("打开成功\n");
	}
	//读文件
	int i = 0;
	char ch[30] = {0};
	for (i = 0; i < 26; i++)
	{
		ch[i] = fgetc(pf);
	}
	printf("%s", ch);

	//关闭文件
	fclose(pf);
	pf = NULL;//置为空指针NULL,防止野指针

	return 0;
}

运行结果:
在这里插入图片描述

fputc(写)

函数原型:

int fputc(int character,FILE*stream);
  • 函数功能:将字符character,写入到stream流中去
  • 返回值:fputc 写入成功时返回写入的字符,失败时返回 EOF

例如:

#include<stdio.h>
int main()
{
	
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	//文件操作
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	else
	{
		printf("打开成功\n");
	}
	//写文件
	char ch = 0;
	for (ch ='a'; ch <= 'z'; ch++)
	{
		fputc(ch, pf);//ch为要写入的字符,pf为要写入的文件指针
	}
	

	//关闭文件
	fclose(pf);
	pf = NULL;//置为空指针NULL,防止野指针

	return 0;
}

接下来我们打开test.txt文件查看:
在这里插入图片描述

fgets(读)

函数原型:

char * fgets ( char * str, int num, FILE * stream );
  • 函数功能:从streaml流中最多读取num个字符放到str所指向的地址处
    返回值:读取成功返回str的指针,读取失败返回NULL

fgets函数会从stream中读取字符,直到遇到下列三种情况之一会停止下来:

读取了n-1个字符(最多读取n个字符但是函数fgets会在末尾添加一个终止符’\0’,所以相当于读取了n-1个字符);
读取到了换行符’\n’;
读取到了文件结束符EOF。
如果读取成功,则返回一个指向str的指针,否则返回NULL。另外,fgets会将读取到的字符串缓存到str中,并自动在末尾添加一个终止符’\0’。

例子:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
		if (NULL == pf)
		{
			perror("fopen");
			return 1;
		}
	char ch[100] = {0};
	fgets(ch,100, pf);
	printf(ch);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述

fputs(写)

函数原型:

int fputs(const char*str,FILE*stream);
  • 函数功能:将字符串str的内存写入到stream流中去
  • 返回值:成功时,将返回非负值。
    出错时,该函数返回 EOF 并设置错误指示器(ferror)。

例如:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	
	fputs("hello world!\n", pf);
	char ch[20] = { "你好!!\n" };
	fputs(ch, pf);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

运行后test.txt文件夹:
在这里插入图片描述

C语言的三种标准流

C语言程序运行的时候会默认打开三个流;
stdin - 标准输入(键盘) 类型FILE*
stdout - 标准输出(屏幕) 类型FILE*
stderr - 标准错误(屏幕) 类型FILE*
这三个流和前面描述的文件流是一样的。

直接上代码使用方法例子1:

#include<stdio.h>
int main()
{
	int ch = fgetc(stdin);//从键盘流中读取到ch
	fputc(ch,stdout);//将ch中的数据写到屏幕上去
	return 0;
}

在这里插入图片描述
例子2:

#include<stdio.h>

struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = { 0 };
	fscanf(stdin, "%s %d %f", s.name, &(s.age), &(s.score));//从键盘读取
	fprintf(stdout, "%s %d %f\n", s.name, s.age, s.score);//输出到屏幕上
}

运行结果:
在这里插入图片描述例2中的fprintf,fscanf的用法其实和printf,scanf的用法一样

fscanf(读)与 fprintf(写)

fscanf函数原型:

int fscanf(FILE* stream,const char*format,...);

scanf函数原型:

int scanf(const char*format,...);

fprintf函数原型:

int fprintf ( FILE * stream, const char * format, ... );

printf函数原型:

int printf ( const char * format, ... );

所以fprintf和fscanf的用法我们都比较好理解了,就是多了一个FILE*类型的流,他们的功能就是:

fpritnf:将格式化数据写入流stream
fscanf:从流stream中读取格式化数据

直接上代码:

#include <stdio.h>

int main()
{
	char str[80];
	float f;
	//打开文件方式读和写
	FILE* pf = fopen("myfile.txt", "w+");
	if (NULL == pf)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fprintf(pf, "%f %s", 3.1416, "PI");
	rewind(pf);//文件流pf关联的位置指示器设置为文件的开头。	
	//读文件
	fscanf(pf, "%f %s", &f,str);	

	//关闭文件
	fclose(pf);
	pf = NULL;
	//打印
	printf("I have read: %f and %s \n", f, str);
	return 0;
}

运行截图:
在这里插入图片描述

fwrite(二进制写入文件)

函数原型:

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

函数功能:

从ptr所指向的内存中向stream中写入count个size大小的内存

返回值:

返回成功写入的元素总数。
如果此数字与 count 参数不同,则写入错误阻止函数完成。在这种情况下,将为流设置错误指示器(ferror)。
如果大小或计数为零,则该函数返回零,错误指示器保持不变。
size_t 是无符号整数类型。
直接上代码演示:

struct S
{
	char name[20];
	int age;
	float score;
};
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "wb");//以二进制形式打开文件
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	struct S s = { "张三",23,95 };
	//以二进制形式写文件
	fwrite(&s, sizeof(struct S), 1, pf);//从s所指向的内存读取数据写入到文件pf中去
	
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

文件夹中的内容:
在这里插入图片描述
证明已经将数据以二进制的形式写进去了,接下来我们就来研究用二进制读取

fread(二进制读取文件)

函数原型:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

函数功能:

从stream流中读取count个size大小的空间放入到ptr所指向的内存处

返回值:

返回成功读取的元素总数。
如果此数字与 count 参数不同,则表示读取时发生读取错误或到达文件末尾。在这两种情况下,都会设置正确的指标,可以分别用 ferror 和 feof 进行检查。
如果大小或计数为零,则该函数返回零,并且流状态和 ptr 指向的内容保持不变。
size_t 是无符号整数类型。
直接上代码:

struct S
{
	char name[20];
	int age;
	float score;
};

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "rb");//以二进制形式打开文件
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	struct S temp = { 0 };
	//以二进制形式写文件
	fread(&temp, sizeof(struct S), 1, pf);//从文件pf中读取数据放到temp指针所指向的内存
	printf("%s %d %f\n", temp.name, temp.age, temp.score);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值