C语言文件操作

         文件我们平时都在使用,那么C语言的文件操作是用来干什么的呢?就比如我们编写通讯录,图书管理系统......在我们完成编写后就会发现数据无法进行保存,在程序退出后数据就消失了,想要在程序运行结束后还可以保存数据,就需要进行文件操作。

 目录

 目录

文件操作

文件的打开和关闭

 文件指针

 文件的打开和关闭

fopen 

fclose 

文件的顺序读写 

fputc 

 fgetc

fputs 

fgets 

fprintf 

fscanf 

fwrite 

fread 

文件的随机读写 

fseek 

ftell 

rewind 

小结 


文件操作

文件的打开和关闭

 文件指针

         我们首先来了解以下文件指针,什么是文件指针呢?

        每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE

        就比如vs2008编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

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

        在不同的环境中,FILE包含的内存可能有些许不同。

        看起来是不是很复杂,但是我们不必对其有太多的关注,我们只需要知道,我们可以通过文件指针来找到所对应的文件。

        那么我们就创建一个FILE*类型的指针变量:

FILE* pf;

 文件的打开和关闭

        那我们应该如何来打开和关闭文件呢?

        在这之前,我们首先要知道,在文件的读写前打开文件,使用结束后应该关闭文件。

并且我们在编写程序或是打开文件的时候,都会返回FILE*的指针变量指向该文件。 

fopen 

        我们一般使用fopen来打开文件: 

        

        我们来看它的参数:FILE * fopen ( const char * filename, const char * mode )filename是文件名,也就是说,第一个参数是想要打开的文件名。mode是方式,那么第二个参数就是打开的方式,那么我们该以何种方式来打开文件呢?方式如下:

        

        那么接下来我们就来打开一个文件,我们就以"w"打开test.txt这个文件(如果该文件不存在,则会自己进行创建)。

        我们进行编写:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	return 0;
}

        这里我们就需要注意,打开文件是可能会失败的,因此我们需要对FILE*进行判断:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	return 0;
}

         在我们完成对打开文件代码的编写后,就需要关闭文件,那么关闭文件的函数又是什么呢?

fclose 

        那么fclose是如何来进行使用的呢?

  

        我们先来看这个函数的参数:FILE * stream,是一个FILE类型的指针,也就是说,我们只需要将创建好的指针变量放进去就可以了。同样的,为了避免指针变量成为野指针,我们需要将其赋为空指针:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行成功后,打开代码所在的文件:

        

        我们可以看到,确实生成了一个名为test.txt的文件。

文件的顺序读写 

        在打开文件之后,我们就需要读写文件,读写的方式有多种,接下来就我们就一一进行介绍: 

fputc 

        fputc是字符输出函数,那么fputc是如何来写文件的呢? 

        

        我们看它的参数:int fputc ( int character, FILE * stream );其中int character是想要写的字符,FILE * stream是文件指针的变量。

        那么我们就来用fputc来写文件,我们将就将a b c d 这几个字符写进文件里:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	fputc('d', pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行成功后,打开文件:

        

        我们可以看到,它确实将a b c d写进去了。

 fgetc

        fgetc是字符输出函数:

         

        它的参数只有一个文件指针,那我们直接对其进行使用,我们读一个,打印一个:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行结果如下:

        

fputs 

        fputs是文本行输出函数: 

        

        那么我们先来看它的参数:int fputs ( const char * str, FILE * stream );我们可以发现它的第一个参数是字符串指针,第二个参数是文件指针,那么,我们接下来就来使用fputs:

#inlclude<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputs("hello world!\n", pf);
	fputs("the world.", pf);//若想换行。直接加上'\n'即可
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行后,打开文件,查看结果:

        

fgets 

        fgets是文本行输入函数,它一次读取一行: 

        

        fgets的参数相比于fputs多了最大读取的个数,那么我们就首先创建char类型的大小为100的数组。如果文本中没有100个元素,会发生什么呢?我们进行测试:

        

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

        我们进行测试:

        

        也就是说,它一次只读取一行,遇到'\0'停止读取。

fprintf 

        fprintf是格式化输出函数。

        那么fprintfprintf有什么区别呢?我们进行对比:

         

        

        我们可以发现,fprintf相比于printf只是多了文件指针这和参数,那么我们创建一个结构体,将结构体中的数据写到文件里面去:

        

#include<stdio.h>
struct S
{
	float a;
	char b;
	int c;
};

int main()
{
	struct S s = { 3.14f,'w',100 };
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fprintf(pf, "%f %c %d", s.a, s.b, s.c);
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行之后,打开文件:

        

        确实写进去了。

fscanf 

        fscanf是格式化输入函数:

        它与scanf有什么区别呢?

         

        

        也是一样的,fscanf多了文件指针这个参数,那我们直接来对其进行使用:

#include<stdio.h>
struct S
{
	float a;
	char b;
	int c;
};

int main()
{
	struct S s = { 0 };
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fscanf(pf, "%f %c %d", &(s.a), &(s.b), &(s.c));
	printf("%f %c %d\n", s.a, s.b, s.c);
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行结果如下:

        

fwrite 

        fwrite是以二进制输出:

         

        我们先来看它的参数:size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );第一个参数是数组地址,第二个是元素大小,第三个是元素个数,第四个是文件指针。

        那我们就创建一个整型数组,将其中的元素存入文件:

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fwrite(arr, sizeof(int), sizeof(arr) / sizeof(arr[0]),pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行之后,打开文件:

        

        我们会发现看不懂,毕竟是以二进制的方式写入的,但是成功写入了,我们接下来进以二进制的方式来读,看写进去的数是否正确。

fread 

        fread是二进制输入:

         

        我们首先来看它的参数:size_t fread(void* ptr, size_t size, size_t count, FILE* stream);可以发现它与fwrite的参数是一致的,那么我们直接使用:

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fwrite(arr, sizeof(int), sizeof(arr) / sizeof(arr[0]), pf);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行结果如下:

        

        成功的读出来了,也证明fwrite成功的写入了。

文件的随机读写 

         在了解完文件的顺序读写后,我们来了解文件的随机读写。

fseek 

         fseek是根据文件指针的位置和偏移量来定位文件指针的:

        

        我们看它的参数:int fseek ( FILE * stream, long int offset, int origin );它的第一个参数是文件指针,第二个参数是偏移量,第三个参数是起始位置。

        那么它究竟有什么用呢?我们先来对偏移量进行了解:

        

        SEEK_SET是起始位置,SEEK_CUR是指针当前位置,SEEK_END是最末尾。

        那么我们进行实验:
        我们先在文件中存a b c d e f,然后继续编写:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

       这是正常读,但是我如果在这时又想读a,那么就该fseek登场了:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	fseek(pf, -2, SEEK_CUR);
	ch = fgetc(pf);
	printf("%c ", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行结果如下:

        

        我们就会发现我们又一次读到了a

ftell 

        ftell会返回文件指针相对于起始位置的偏移量: 

        

        它的参数只有文件指针,那我们直接对其进行使用:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	int pos = ftell(pf);
	printf("\n%d \n", pos);
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行结果如下:

        

rewind 

        rewind是让文件指针的位置回到起始位置:

        

        它的参数也是只有文件指针,那我们在让它返回起始位置后再进行打印:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	rewind(pf);
	ch = fgetc(pf);
	printf("%c ", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

        运行结果如下:

        

        成功打印。

小结 

        就到这里吧,其实关于文件操作还有很多内容,比如文件的结束判断,文件的缓冲区啊之内的,小编实力有限,就不在这里进行讲解啦。好啦 ,我们这次就先到这里,我们C++见!

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值