C语言————文件操作

1. 为什么使用文件

使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。

2. 什么是文件

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

2.1 程序文件

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

2.2 数据文件

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

本章讨论的是数据文件。

在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显 示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理 的就是磁盘上文件。

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

文件名包含3部分:文件路径+文件名主干+文件后缀

例如: c:\code\test.txt

为了方便起见,文件标识常被称为文件名。

3. 文件的打开和关闭

3.1 文件指针

3.2 文件的打开和关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。

ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

我们来看看这两个函数的使用。

打开文件


FILE * fopen ( const char * filename, const char * mode );

 文件访问模式(打开方式):

 关闭文件

int fclose ( FILE * stream );

直接找到该文件指针,对其关闭就可以了。

同时注意的是:关闭后,将该指针置空,防止以后不小心用到,形成野指针。

现在,我们来通过示例来感受一下:

示例:

#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("code_test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");//如果文件打开失败,打印失败原因
		return 1;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

运行上述代码,将会以“w”只写的方式打开一个 “code_test.txt”的文件,如果没有此文件,将会先建立一个这样的新文件,再打开。这一切都是在该工程目录的路径下。

运行前:

 运行后:

我们可以看到,文件被创建出来,因为没有进行写入操作,所以,什么内容都没有,是空的。

下面,我们来看看如何读写。

 4  文件的顺序读写

关于文件的顺序读写会用到以下几种函数:

4.1 fputc

int fputc ( int character, FILE * stream );

int character———需要输入的字符,FILE * stream——文件指针

现在,我们用它往文件中写入26个英文字母

代码:

//fputc
//int fputc ( int character, FILE * stream );
//成功:返回写入的字符值
//失败:返回EOF
void test5()
{
	FILE* pf = fopen("code_test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	//写入26英文字母
	for (int i = 0; i < 26; i++)
	{
		printf("%c ", fputc('a' + i, pf));//根据返回值,同时打印26英文字母
	}
	
	fclose(pf);
	pf = NULL;
}

运行前,code_test文件中是空白的:

 运行后,就会写入26个英文字母:

4.2 fgetc

int fgetc ( FILE * stream );

利用fgetc函数,就可以从刚才的文件中读到写入的26个英文字母

代码:

//fgetc
//int fgetc ( FILE * stream );
void test6()
{
	FILE* pf = fopen("code_test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	//读取写入的26个英文字母
	char temp = 0;
	for (int i = 0; i < 26; i++)
	{
		temp=fgetc(pf);
		printf("%c ", temp);
	}

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

运行结果:

4.3 fputs和fgets

前面的是输入单个字符,现在我们来输入一行字符串

int fputs(const char *str, FILE *stream)

把字符串写入到指定的流 stream 中,但不包括空字符。

代码:

//fputs---写一行数据
void test1()
{
	//打开文件
	//相对路径(在工程路径中)
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return ;
	}
	//写文件
	fputs("hello world", pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

现在利用fgets将写入的信息读出来:

char *fgets(char *str, int n, FILE *stream) 

从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

示例:

//fgets——读入一行数据
//注意:1.遇到换行符,停止读入。
//		2.读取(num-1)个字符
void test2()
{
	char str[100] = { 0 };
	//打开文件
	//相对路径(在工程路径中)
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return ;
	}
	//读文件
	fgets(str, 10, pf);
	printf("%s\n", str);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

我们只读取了9个字符,所以应该读到:hello wor这9个字符。

运行结果:

4.4 fscanf和fprintf

那如果,要写入不同类型的数据呢?

比如:结构体数据如何?

这就需要用到这两个函数:fscanf和fprintf

代码:

struct S
{
	char name[20];
	int age;
};
void test3()
{
	struct S s = { "张三",20 };
	//打开文件
	//相对路径(在工程路径中)
	FILE* pf = fopen("test1.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	//写文件
	fprintf(pf, "%s %d", s.name,s.age);
	
	//关闭文件
	fclose(pf);
	pf = NULL;
}
//
void test4()
{
	struct S s1 = { 0 };
	//打开文件
	//相对路径(在工程路径中)
	FILE* pf = fopen("test1.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	//读文件
	fscanf(pf, "%s %d", s1.name,&s1.age);
	printf("%s %d", s1.name, s1.age);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

 如上图所示,代码运行前,文件中是空白的,运行结束后,将信息写入到文件中去。

5. 文件的随机读写

前面提到的是顺序读写,因为像fgetc这样的函数,他只能一个一个的往下读,是无法返回的。比如说:利用fgetc读到一半想要从头开始,这是做不到的。

那如何让我们想读哪就读哪,这就需要以下函数

5.1 fseek

根据文件指针的位置和偏移量来定位文件指针。

int fseek ( FILE * stream, long int offset, int origin );

offset——相对于origin参数位置的偏移量

origin——表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:

来看示例:

 我们还是利用前面写入了26个英文字母的文件来读取。

void test7()
{
	FILE* pf = fopen("code_test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	//读取写入的26个英文字母
	char temp = 0;
	//a
	temp = fgetc(pf);
	printf("%c\n", temp);
	//b
	temp = fgetc(pf);
	printf("%c\n", temp);
	//c
	temp = fgetc(pf);
	printf("%c\n", temp);
	//fgetc每读一次,文件指针向后偏移一位
	//通过fseek再读a
	fseek(pf, -3, SEEK_CUR);//指针-3回到a的位置
	temp = fgetc(pf);
	printf("%c\n", temp);
    //关闭文件
	fclose(pf);
	pf = NULL;
}

 

5.2 ftell

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

long int ftell ( FILE * stream );

比如上面的代码,我们读到字符c时,忘记偏移量是多少了,就可以利用ftell函数来看一下此时的偏移量。

代码:

void test7()
{
	FILE* pf = fopen("code_test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	//读取写入的26个英文字母
	char temp = 0;
	//a
	temp = fgetc(pf);
	//b
	temp = fgetc(pf);
	//c
	temp = fgetc(pf);
	//ftell----返回文件指针相对于起始位置的偏移量
	int move = ftell(pf);
	printf("%d\n", move);//3
	//关闭文件
	fclose(pf);
	pf = NULL;
}

运行结果:

 

5.3 rewind

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

void rewind ( FILE * stream );

当我们想从头开始读时,利用rewind就可以了。

示例:

void test7()
{
	FILE* pf = fopen("code_test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	//读取写入的26个英文字母
	char temp = 0;
	//a
	temp = fgetc(pf);
	//b
	temp = fgetc(pf);
	//c
	temp = fgetc(pf);
	//rewind-----让文件指针的位置回到文件的起始位置
	rewind(pf);
	int move = ftell(pf);
	printf("%d\n", move);//0----偏移量
	//关闭文件
	fclose(pf);
	pf = NULL;
}

 小结

文件操作内容还有很多,在这里就不依次介绍。谢谢观看!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值