【C语言】文件操作详解

目录

一.文件概念

1.数据文件、程序文件

2.文件名

3.二进制文件、文本文件

二.文件打开、关闭

1.流

2.标准流

3.文件指针

 ​编辑

4.文件打开、关闭 

三.文件顺序读写

 1.fgetc

 2.fgets​编辑

3.fsancf  

4.fread

四.文件随机读写

1.fseek

2.ftell

3.rewind

五.文件结束判定


一.文件概念

1.数据文件、程序文件

程序的数据是储存在内存中的,一旦程序结束,内存回收,数据就丢失,无法长久地储存数据,因此出现了文件这一概念。磁盘(硬盘)上的文件是文件,就按功能进行分类,可以分为数据文件程序文件两种,程序文件包括源文件程序(.c),目标文件(.obj),可执行程序(.exe)等,本文讨论的是数据文件。

2.文件名

文件名:一个文件需要有一个唯一的标识以便识别和查找文件,文件名就能做到这个功能。文件名包含三部分:文件路径+文件名主干+文件后缀,例如:C:\code\test.txt

3.二进制文件、文本文件

数据文件按照数据的组织形式可以分为文本文件和二进制文件。数据在内存中以二进制的形式存储,如果不加转换的输出到外存文件中,就是二进制文件。如果在外存上以ASCII码的形式进行存储,就是文本文件。下图以储存10000进行举例:

二.文件打开、关闭

1.流

在进行正式的文件操作之前,首先要了解“流”这一概念。数据需要流入流出,把数据从不同的设备进行输入输出的操作抽象为流操作,可以将流想象成流淌着字符的河流。想向流里写数据,或者从流中读取数据,都是要打开流,然后操作。

2.标准流

我们从键盘上输入数据,向屏幕输出数据,C语言程序在启动的时候已经默认打开了三个流。

stdin:标准输入流,从键盘输入,scanf函数就是从标准输入流中读取数据。

stdout:标准输出流,输出至显示器界面,printf就是将信息输出到标准输出流当中。

stderr:标准错误流,将错误信息输出到显示器界面。

值得注意的是,输入输出是站在程序的角度而言的,下图清晰展现了这个过程:

3.文件指针

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

不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。下图便是创建了一个FILE* 类型的指针变量pf1:
 

 

4.文件打开、关闭 

接下来就能正式打开关闭文件了。 在编写程序的时候,在打开文件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建立了指针和文件的关系。ANSIC规定使用 fopen 函数来打开文件, fclose 来关闭文件。

//打开⽂件 filename:文件名    mode:打开模式      
FILE * fopen ( const char * filename, const char * mode );

//关闭⽂件
int fclose ( FILE * stream );


//例如
FILE* pf = fopen("text.txt","w");
//检验是否为空指针
if(pf == NULL)
{
    perror("fopen");
    return 1;
}

fclose(pf);
//赋值空指针,保证安全性
pf = NULL;

其中打开模式中,有多种选择,如“w”只写,该情况下只允许输出数据(也就是程序向文件输出数据),若文件不存在则创建一个与输入文件名相同的文件。“r”则对应只读,若文件不存在则报错。“a”对应追加,由于使用"w"只写,会先清空先前的内容再输出数据,在写因此有了“a"追加的方式,能保留之前的内容。

在这三种基础模式上,再加上“wb” "rb" "ab",加上b表明输入/输出形式是以二进制形式的。而“w+” "r+" "a+"则是读写都包括的。

三.文件顺序读写

在文件的顺序读写中,需要用到以下几个函数。不过在此需要提一下为何称为“顺序”读写呢?顾名思义,以下几个函数都是按着顺序进行读写,以fgetc每次读取一个字符为例,在进行一次读后,下一次读取时光标会自动跳到下一个字符处,这样就能自动读取下一个字符,这样按着文本顺序进行操作称为顺序读写。

在文件操作中,读写都是成对出现,使用方法都是相似的,因此此处只重点介绍fgetc、fgets、fscanf 、fread

 1.fgetc

fgetc适用于所有输出流(标准输出流+文件输出流),既然是输出流,打开文件时就必须以“读”(“r”、"r+")的模式打开。这是读取一个字符的函数,如果成功读取字符的话,返回的是字符的ASCII码值,如果读取到文件末尾或者读取失败的时候,则返回EOF(-1),以下代码展现了基本的使用方法。

int main()
{
	FILE* pf = fopen("text.txt", "r");
    //必要的检验
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	for (int i = 0; i < 20; i++)  //使用循环读取20个字符并打印
	{                             //每次循环光标自动后移一位
		char ch = fgetc(pf);//此处也可以进行判断返回值是否是-1在跳出循环
		printf("%c", ch);
	}

	char ch = 0;
	while ((ch = fgetc(pf)) != EOF) //如此能打印文本全部字符
	{
		printf("%c", ch);
	}
	
    //必要的收尾步骤
	fclose(pf);
	pf = NULL;
	return 0;
}

 2.fgets

与上文的fgetc同理,不过区别在于fgets用于读取一整行的字符。fgets有三个参数,分别是读取字符串存放的地址、最多读取的字符个数、读取文件的指针。使用时还要注意几点:

1.fgets会自动补\0,因此如果要读取的一行字符个数大于指定的最大读取个数,实际只会读取最大读取个数-1个字符,例如最大读取个数num取10,但一行字符数超过了10,它只会读取9个字符然后补\0

2.fgets会读取 \n( \n也是属于一个字符),读取到 \n后会直接补\0

3.fgets返回char*,如果文件读取失败或者读取到文件末尾会返回NULL(空指针)

作者在此用较为简单的表达自己实现了函数my_fgets来达到fgets的功能,以便理解

char* my_fgets(char* str, int num, FILE* pf)
{
	int i = 0;
	char* ret = str;
	while (num > 1)
	{
		//读到文件末尾返回NULL
		if (fscanf(pf, "%c", &str[i]) != EOF)
		{
			if (str[i] == '\0')
			{
				return str;
			}
			if (str[i] == '\n')
			{
				i++;
				break;
			}
			i++;
			num--;
		}
		else
			return NULL;
	}
	str[i] = '\0';
	return str;
}

3.fsancf  

与平常使用的scanf相差无几,唯一的区别就是在最前加了个文件指针,指明读取数据来源。读取失败或读取到文件末尾返回EOF,在上述实现my_fgets中就使用了该函数,可以进行参考。

4.fread

fread和fwrite都是以二进制形式读写,因此打开文件的模式必须是“rb”或“wb”。

参数共有四个:目标地址、元素字节大小、元素个数、文件流。返回值是size_t类型,即成功读取的元素个数。

//以二进制形式读数据
fread(arr,sizeof(arr[0]),5,pf);

四.文件随机读写

所谓随机读写就是与顺序读写相反,读取文件的“光标”可以指定或改变,不像顺序读写一样默认自动后移一位。在文件随机读写中主要是使用fseek、ftell、rewind三个函数。

1.fseek

根据⽂件指针的位置和偏移量来定位文件指针(文件内容的光标)。其中stream是文件指针的位置,offset是相对源的偏移量,origin是源。对于源的定义,可以参考一下几个位置。

2.ftell

返回文件相对起始位置的偏移量。

3.rewind

让文件指针的地址回到文件的起始地址。(将光标重新移回起点)适用于对文件进行操作后再进行第二次操作前。

五.文件结束判定

在打开一个流的时候,这个流上有两个标记值,在读取文件到文件末尾或者发生错误时,标记值就会改变,这样我们就有了两个函数来判断文件读取结束的原因了。它们分别是feofferror。可以按照如下使用:

//判断是什么原因导致读取结束的
if(feof(pf))
{
    printf("遇到文件末尾,读取结束\n");
}
else if(ferror(pf))
{
    perror("error”);
}

return 0;

  • 31
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值