C语言文件操作(一)

(一)文件

什么是文件?

为了便于理解,可以把文件看作是一个结构体,里面存放着数据,这些数据就反映了文件的属性。后面将要提到的文件指针fp,实际上就指向这个结构体,当我们要调用一个文件的时候,常常会用到这个指针。

如上所说,文件是一个数据的集合,它常常被储存在外部设备上(如U盘或硬盘),当需要调用的时候,系统得到调用的指令,把目标文件临时取出,放入内存供使用。

而在系统中,文件结构体已经被定义了,如下:

#include<stdio.h>
struct iobuf{
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf
int _bufsiz;
char *_tmpfname;
};

在这些成员当中,只需要理解char*_ptr,即下面的位置指针。

(二)文件指针和位置指针

1.位置指针

位置指针_ptr是文件结构体中的成员之一。当某个文件要被调用,系统就把它从外部设备临时调到内存缓冲区中,而位置指针_ptr就指向了缓冲区下一个待操作的字节,操作一个就往后移动一位,直到末尾。
很容易看出,_ptr的指向在发生变化。

2.文件指针

#include<stdio.h>
FILE *fp;//定义了一个指向文件的指针

文件指针就是上述的fp,它指向该文件(文件的结构体),是文件类型的指针,因此要用 FILE*fp来表示。
只要是在同一个文件上操作,fp的指向都不会发生变化。

(三)打开文件fopen()函数

1.函数原型:

#include<stdio.h>
FILE *fp;
fp = FILE *fopen(const char *path,const char *mode);

依次输入(“文件路径”,“使用方式”)
返回值是一个文件指针,所以可以直接把它的返回值赋给fp。

2.文件路径

如果只写出文件名,默认目标文件的路径为当前程序文件所在的路径,如果使用文件本身的名字,需要加上双引号。例如:

fopen("test.txt","r");//只能打开test.text这一种文件

如果要用变量名来表示文件的名字,(只有在这种情况下,才可以给目标文件取别名)就把变量名作为文件的别名。例如:

char name[10];//可以根据需求打开不同的文件
fgets(name,stdin);//用户输入文件名,此处用name替代
fopen(name,"r");

如果目标文件和程序文件不在同一个路径下,需要明确写出目标文件的路径。例如:

fopen("D:\\USERS\\COMPUTER\\test.txt","r");

注意!这个时候,必须要用双引号括出文件的路径,言外之意,这个时候不能用变量名表示!一旦表示,就会变成一个字符串,失去了变量名的意义。

3.文件的使用方式

一共包括了 r,w,a,+,b这几种字符,下面是他们各自的含义。

  • r :只读,且目标文件不存在时不会自动创建
  • r+ :可读可写,且目标文件不存在时不会自动创建
  • w :只写,且目标文件不存在时会自动创建
  • w+ :可写可读,且目标文件不存在时会自动创建
  • a :追加,且目标文件不存在时会自动创建
  • a+ :可追加且可读,且目标文件不存在时会自动创建

注:(只要在上述字母后写一个b,即打开二进制文件)


注意:
(1)当以w或a的形式打开一个不存在的文件,这个时候系统会自动创建一个,如果文件名不加后缀(txt),系统会默认创建一个二进制文件。
(2)当目标文件存在,又以w的形式打开,那么原来的内容会被全部删除,只能新写入内容。
(3)当目标文件存在,又以a的形式打开,那么新写入的内容就会接在原来的内容后面。
(4)当目标文件不存在,以a打开等价于以w打开。


4.附上一个打开文件的小栗子

#include<stdio.h>
int main()
{
	FILE *fp;
	fp = fopen("example.txt","w");
	if(fp!=NULL)
		printf("文件打开成功!");
	else
		printf("文件打开失败!");
	return 0;
}

(四)关闭文件fclose()函数

1.函数原型

#include<stdio.h>
int fclose(FILE *fp);

打开了一个文件一定不要忘记关闭它!否则会一直在内存缓冲区中占用内存空间。
fclose()函数比较简单,只需要输入所需要关闭文件的文件指针fp即可。

2.小栗子

把上面打开文件的函数关闭即可。

#include<stdio.h>
#include<stdlib.h>//为了使用exit
int main()
{
	FILE *fp;
	fp = fopen("example.txt","w");
	if(fp!=NULL)
	{
		  printf("文件打开成功!");
	else
	{
		   printf("文件打开失败!");
		   exit(-1);//程序异常终止
	}
	fclose(fp);
	return 0;
}

(五)字符读取函数fgetc()

1.原型

#include<stdio.h>
int fgetc(FILE *stream);//stream是文件指针

2.作用

从目标文件中读取一个字符,如果读取到文件的末尾,就返回EOF(-1)。

对于其返回值:
返回的是读取到的字节,因此可以利用这一点写出如下的表达:

printf("%c",fgetc(fp));
  • 如果是一个文本文件返回的是该字符的ASCLL码,ASCLL码的范围是0~255,这时虽然可以以是否返回EOF作为判断到达末尾的标准,但是细想,如果程序出现错误,也会返回EOF,那么,当返回了一个EOF的时候,到底是到达了末尾还是程序出现了错误呢。所以,即使是一个文本文件,还是要用下面讲的feof()来判断是否到达文件末尾。

  • 如果是一个二进制文件返回的是相应的0、1、-1三种情况,这时,不能以是否返回EOF来作为判断标准!!!此时需要用到feof()函数专门来判断是否到达文件的末尾。

3.feof()函数——专用于判断是否到达文件末尾

eof=end of file.

原型

#include<stdio.h>
int feof(FILE *stream);

fp指向文件结构体,位置指针_ptr一个字节一个字节向后移动,如果到达末尾,返回非0。

feof()的两种用法

对于文本文件,现在的首要目的是判断函数返回EOF是遇到了错误还是到达了文件末尾。
第一种

#include<stdio.h>
#include<stdlib.h>
int main()//判断一个文本文件返回EOF是遇到了错误,还是到达了末尾
{
	FILE *fp;
	fp = fopen("example.txt","r");
	if(fp!=NULL)
	{
		printf("文件打开成功!\n");
		while(fgetc(fp)!=EOF)
		{
			printf("文件浏览成功!\n");
		}
		if(!feof(fp))//返回非零则到达末尾
		{
			printf("文件没有读到末尾!遇到了错误!\n");
		}
		else
		{
			printf("文件已经读到了末尾!\n");
		}
	}
	else
	{
		printf("文件打开失败!");
		exit(-1);
	}
	fclose(fp);
	return 0;
}

第二种

#include<stdio.h>
#include<stdlib.h>
int main()//判断一个文本文件返回EOF是遇到了错误,还是到达了末尾
{
	FILE *fp;
	fp = fopen("example.txt","r");
	if(fp!=NULL)
	{
		printf("文件打开成功!\n");
		int i=0,j=0;
		while(fgetc(fp)!=EOF)
		{
			i++;
		}
		rewind(fp);
		while(!feof(fp))//到达末尾则返回非零
		{
			j++;
			fgetc(fp);
		}
		printf("浏览循环了%d次,验证是否到达末尾循环了%d次\n",i,j);
	}
	else
	{
		printf("文件打开失败!");
		exit(-1);
	}
	fclose(fp);
	return 0;
}

输出的结果是:浏览循环了12次,验证是否到达末尾循环了13次
究其原因,无非就是feof再判断的时候需要把末尾的EOF作为循环内容再循环一次。而fgetc一读取到EOF就退出循环了。
因此,有时候使用第二种方法会对程序造成影响,这个时候就需要我们做选择了。当然,第一种用fgetc和feof搭配着使用是最好的。


然而,我在写第二种的时候出现了一点麻烦,下面是我最开始的版本,里面有两个问题。
问题就出在这个循环。

		while(!feof(fp))//到达末尾则返回非零
		{
			j++;
		}

把正确版本的这个部分放在下面供比较:

        rewind(fp);
		while(!feof(fp))//到达末尾则返回非零
		{
			j++;
			fgetc(fp);
		}

错误的版本比正常的少了rewind 和循环中的fgetc(fp)。
rewind()是把光标返回文件开头的意思,后面会详细讲到。
这里需要注意!!
feof只能用做判断,它在判断之后并不会自动读取下一个字节!!所以这时候需要借助fgetc()来移动光标。
所以,当我们要用feof作判断的时候,一定要先读取,再判断。


内容有点多,下一篇文章继续…

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值