文件指针(c语言详细笔记)

文件指针(c语言详细笔记)

如果你是寻找常用的缓冲文件系统函数,可直接跳到文章末尾.

一、数据流

数据流借用文件指针的移动来访问数据,文件指针目前所指的位置即是要处理的数据,经过访问后文件指针会自动向后移动。,每个数据文件后面都会有一个文件结束符号(EOF),用来告知该数据文件到此结束。若文件指针指到EOF时,则表示数据已访问结束。

二、文件

文件是指存放在外部存储介质(可以是磁盘、光盘、磁带等)上的数据集合、操作系统对外部介质上的数据是以文件形式进行管理的。
为标识一个文件,都必须有一个文件名作为访问文件的标志,其一般结构为 文件名.扩展名 。通常情况下一个包括盘符名、路径、主文件名和扩展名四部分信息。

程序在内存运行过程中与外存(外部存储介质)交互主要是通过以下两种方法:
1、以文件为单位将数据写到外存中;
2、从外存中根据文件名读取文件中的数据。

c语言支持的是流式文件,即前面说到的数据流,他把文件看作一个字节写,以字节为单位进行访问,没有记录的界限,即数据的输入和输出的开始和结束仅受程序控制,而不受物理符号(回车换行符)控制。

根据不同的角度对文件进行分类:
1、根据文件依附的介质:(1)普通文件是指驻留在磁盘或其他外部介质上的一个有序数据集。(2)设备文件是指与主机相连的各种外部设备。
2、根据文件的组织形式:(1)顺序读写文件,是指按从头到尾的顺序读出或写入的文件。(2)随机读写文件大都使用结构方式来存放数据,即每个记录的长度是相同的,因而通过计算便可直接访问文件中的特定记录。
3、根据文件存储形式:(1)ASCII码文件也称为文本文件,这种文件在磁盘中存放每个字符对应一个字节,用于存放对应的ASCII码。(2)二进制文件,是按二进制编码方式来存放文件的。

二进制文件和ASCII码文件的主要区别在于:
1、从存储形式上看,二进制文件是按该数据类型在内存中的存储形式存储的,而ASCII码文件则将该数据类型转换为可在屏幕上显示的形式来存储的。
2、从存储空间上来看,ASCII存储的方式所占空间比较多,而且所占空间大小与数值大小有关;
3、从读写时间上看,由于ASCII码文件在外存上以ASCII码存放,而在内存中的数据都是以二进制存放的。所以当进行文件读写时,要进行转换,造成存储速度较慢,对于二进制文件来说,数据就是按照在内存中的存储形式在内存上存放的。所以不需要进行这样的转换,在存取速度上较快。
4、从作用上看,由于ASCII文件可以通过编辑程序,进行建立和修改,也可以通过DOS中的type命令显示出来。因而ASCII文件通常哟怒存放输入数据及程序的最终结果,而二进制就不能显示出来所以用于暂存程序的中间结果,供另一段程序读取。

三、文件类型的指针

#include<stdio.h>
typedef struct{
	// 缓冲区“满”或“空”的程度
	short level;
	// 文件状态标志
	unsigned flags;
	// 文件描述符
	char fd;
	// 如无缓冲区则不读取字符
	unsigned char hold;
	// 缓冲区的大小
	short bsize;
	// 数据缓冲区的读写位置
	unsigned char *baffer;
	// 指针指向当前文件的读写位置
	unsigned char *curp;
	// 临时文件,指示器
	unsigned istemp;
	// 用于有效性检查
	short token;
}FILE;
FILE*fp;

四、打开文件

FILE *fopen(char *filename,char *mode);
使用mode模式打开指定- NNNNNNNNNNNN
B的filename文件,如打开文件成功返回有FILE类型的指针,如打开文件失败,则返回NULL;
第一个参数filename用来设定打开的文件,第二个参数用来设定打开的文件类型和指定文件的访问模式,必须是字符串格式,头尾必须用双引号括起来。

文件使用方式意义
“rt”只读打开一个文本文件 ,只允许读文件
“wt”只写打开或建立打开一个文本文件,只允许写数据
“at”追加打开一个文本文件,并在文件末尾写数据
“rb”只读打开或建立一个二进制文件,只允许读数据
“wb”只写打开或建立一个二进制文件,只允许写数据
“ab”追加打开一个二进制文件,并在文件末尾写数据
“rt+”读写打开一个文本文件 ,允许读和写
“wt+”读写打开或建立一个文本文件,允许读和写
“at+"追加打开一个文本文件,允许读,或在文件末尾写数据
“rb+”读写打开一个二进制文件 ,只允许读和写
“wb+”读写打开或建立一个二进制文件,允许读和写
“ab+"追加打开一个二进制文件,允许读,或在文件末尾写数据
//以只读方式打开一个可执行文件在相同路径下的文本文件test.txt
FILE *fp;
fp=fopen("test.text","r);
// 打开一个e盘下code文件夹下的exce文件data.xls
//嵌入式文件方法
//方法1
FILE *fp2;
fp2=fopen("e:\\code\\data.xls","r");
//方法2
FILE *fp3;
fp3=fopen("e:/code/data.xls","r");

方法一中指定路径时用了两个反斜线“\”,第一个表示转义字符,第二个表示根目录,方法二改用正斜线“/”也可以。

//交互式文件方法
FILE *fp;
char fiename[40];
gets(filename);
fp=fopen(filename,"r");

当打开一个文件时,需要通知给编译系统一下三个信息:
1、需要打开的文件名
2、使用文件的方式
3、让哪一个指针变量指向被打开的文件

对于文件的使用方式有一下几点说明:
1、文件使用方式由r,w,a,t,b,+,x等六个字符组成,各个字符的含义:

r(read)
w(write)
a(append)追加
t(text)文本文件,可省略不写
b(binary)二进制文件
x(xls)excel文件,可省略不写
+读和写

2、凡是用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。
3.凡用“w”打开的文件只能像该文件写入,若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个文件夹。
4.若要向一个已存在的文件中追加新的信息,则只能用“a”方式打开文件,若此时此文件不存在,则会新建一个文件。
5.在打开一个文件时,如果出错,fopen将返回一个空指针NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。
常用以下程序段打开文件:

//如果指针为空则表示不能打开e盘code文件夹下的test.txt文件,则给出信息
FILE *fp;
fp=fopen("e:\\code\\test.txt","r");
if(fp==NULL){
	printf("\n不能打开e:\\code\\test.txt file!");
	getchar();
	exit(1);
}

6.标准输入文件(键盘),标准输出文件(显示器),标准出错输出(出错信息)是由系统打开的,可直接使用。

五、关闭文件

int fclose(FILE *fp);
将文件指针fp所指的文件关闭,若返回0,则表示关闭成功,若返回非0值则表示有错误发生。
fclose(fp);
在程序中,一个文件使用完毕后,若采用读取模式打开文件,可以不必做关闭文件的操作;若采用写入模式,一定要使用fclose()关闭文件,否则最后放在缓冲区的数据无法写会文件,从而发生数据遗失的情况。这是因为当向文件写数据时,是先将数据写到缓冲区,带缓冲区充满后再整块传送到磁盘上,如果程序结束时,缓冲区尚未充满,则其中的数据并没有传到磁盘上,必须使用fclose()函数关闭文件,强制系统将缓冲区的所有数据传送到磁盘上,并释放该文件指针变量;否则这些数据可能知识被送到了缓冲区中,而并没有真正写入到磁盘文件中。
由系统打开的标准设备文件,系统会自行关闭。

六、获取文件属性

int fileno(FILE *fp);
返回所打开文件指针fp对应文件描述之(handle_no)。当打开文件成功后,操作系统会自动赋予一个号码,此号码用来代表所打开的文件,所在头文件是stdlib.h

long filelength(int handle_no);
返回文件描述字(handle_no)对应的文件大小,以字节为单位。所在头文件为io.h

FILE *fp;
int fno,fsize;
fp=fopen("e:\\code\\test.txt","rt");
fno=fileno(fp);
fsize=filelength(fno);
fclose(fp);
// 采用交互式文件方式打开指定文件,若文件打开成功,则显示该文件的大小(byte);若文件打开失败,则提示出错信息。
#include<stdio.h>
#include<stdlib.h>
#include<io.h>
#define LEN 100
void main(){
	FILE *fp;
	char filename[LEN];
	int fno,fsize;
	printf("请输入要打开文件的完整路径及文件名:");
	gets(filename);
	fp=fopen(filename,"r");
	if(fp==NULL){
		printf("\n打开文件失败,%s可能不存在\n",filename);
		exit(1);
	}
	fno=fileno(filename);
	fsize=filelength(fno);
	printf("\n%s文件打开成功,文件大小%dBytes\n",filename,fsize);
	fclose(fp);
}

七、文件顺序读写

文件的读写方式分为顺序读写和随机读写。
顺序读写时指,将文件从头到尾逐个数据读出或写入。文件的读写时通过读函数实现的,
单字符读写函数分别是:fgetc和fputc。
字符串读写函数分别是:fgets和fputs。
格式化读写函数分别是:fscanf和fprintf。
数据块读写函数分别是:fread和fwrite。

1、单字符读写函数

int fgetc(FILE *fp);
读取文件中fp目前所指文件位置中的字符,读取完毕,文件指针自动往下移一个字符位置,若文件指针已经到文件结尾,则返回-1;
cg=fgetc(fp);
其意义是从fp所指的文件中读取一个字符并送入ch中。

对于fgetc函数的使用有以下几点说明:
(1).在fgetc函数调用中,读取的文件必须是以读或读写方式打开的;
(2).读取字符的结果也可以不给字符变量赋值。
(3).在文件内部有一个位置指针,用来指向文件的当前读写位置。在文件打开时,该指针总是指向文件的第一个字节。使用fgetc函数后,该位置指针将自动向后移动一个字节。因此可连续多次使用fgetc函数,读取多个字符。应注意文件指针和文件内部的位置指针不是一回事。文件指针是指向整个文件的,需在程序中定义说明,只要不重新赋值,文件指针的值是不变的。文件内部的位置指针用以指示文件内部的当前读写位置,每读写一次,该指针自动向后移动,它不需在程序中定义说明,而是有系统自动设置的。

#include<stdio.h>
#include<stdlib.h>
#include<io.h>
#define LEN 100
int main(){
	FILE *fp;
	char filename[LEN];
	int fno,fsize;
	char ch;
	printf("请输入要打开文件的完整路径及文件名:");
	gets(filename);
	fp=fopen(filename,"rt");
	if(fp==NULL){
		printf("\n打开文件失败,%s可能不存在\n",filename);
		exit(1);
	}
	fno=(fileno(fp));
	fsize=filelength(fno);
	printf("\n%s文件打开!\n",filename);
	printf("\n文件大小%dBytes\n",fsize);
	printf("\n文件内容为:");
	while((ch=fgetc(fp))!=EOF)
		printf("%c",ch);
	fclose(fp);
	printf("\n\n");
	return 0;
}

关于符号常量EOF:
(1)、在对ASCII码文件进行读入操作时,如果遇到文件为,则读操作函数返回一个文件结束标志EOF,其值在头文件stdio.h已被定义值为-1;
(2)、在对二进制文件进入读入操作时,必须使用库函数feof()来判断是否遇到文件尾。

2、写单字符函数fputc()

int fputc(char ch,FILE *fp);
把字符ch写入文件指针fp所指向文件的位置,成功时返回字符的ASCII码,失败时返回EOF(在stdio.h中,符号常量EOF的值等于-1)。
FILE *fp;fputc('a',fp);
其意义是把字符a写入fp的指向文件中。

fputc函数的使用说明:
(1)被写入的字符可以用写、读写、追加方式可打开。用写或读写方式打开一个已存在的文件时,将清除原有的文件内容,写入字符从文件首开始。如需保留原有文件内容,希望写入的字符从文件末开始存放,必须以追加方式打开文件,被写入的文件若不存在,则创建该文件。
(2)每写入一个字符,文件内部位置指针向后移动一个字节。
(3)fputc函数有一个返回值,如写入成功则返回写入的字符,否则返回一个EOF。可以此来判断写入是否成功。

#include<stdio.h>
#include<stdlib.h>
#include<io.h>
#include<ctype.h>
#include<string.h>
#define LEN 100
int main(){
	FILE *fp;
	char filename[LEN],data[LEN];
	int fno,fsize,i;
	char ch;
	printf("写文件程序...\n");
	printf("请输入要打开文件完整路径及文件名:");
	gets(filename);
	fp=fopen(filename,"a+");
	if(fp==NULL){
		printf("\n打开文件失败,%s可能不存在\n",filename);
		exit(1);
	}
	fno=fileno(fp);
	fsize=filelength(fno);
	printf("\n%s文件打开!\n",filename);
	printf("\n文件大小%dBytes\n",fsize);
	printf("\n文件内容为:");
	while((ch=fgetc(fp))!=EOF)
		printf("%c",ch);
//	这里添加数据 
	while(1){
		printf("\n\n请问是否要添加数据(Y/N):");
		if(toupper(getchar())=='Y'){
			printf("\n\n请输入要添加的数据:");
			getchar();
			gets(data);
			for(i=0;i<strlen(data);i++){
				fputc(data[i],fp);
			} 
		}
		else{
			fclose(fp);
			break;
		}
	}
//	检测是否写入了数据
	fp=fopen(filename,"r");
	if(fp==NULL){
		printf("\n写入数据失败!\n");
		exit(1);
	}
	while((ch=fgetc(fp))!=EOF)
		printf("%c",ch); 
	fclose(fp);
	return 0;
}

3、字符串读写函数

(1)读字符串函数fgets()
char *fgets(char *str,FILE *fp);

FILE *fp;
char str[10];
fp=fopen("e:\\code\\test.txt","rt");
while(fgets(str,10,fp)!=NULL)
	printf("%s",str);

其意义是从fp所指的文件中读取10个字符送入数组str中,接着再将str字符串打印出。若文件读不到数据则会返回NULL,此时会离开循环。

(2)写字符串函数fputs()
int fputs(char *str,FILE *fp);

FILE *fp;
char str[10];
fp=fopen("e:\\code\\test.txt","rt");
gets(str);
fputs(str,fp);

其意义是把字符串str中的内容写入文件指针fp所指的文件中。

4、格式化字符串读写函数

(1)格式化字符串读写函数fscanf()
int fscanf(FILE *fp,"格式化字符串",输入项地址表);
从文件指针fp所指向的文件中按照格式字符串指定的格式,将文件中的数据送到输入项地址中。若读取的数据成功则返回所读取数据的个数,并将数据按照指定格式存入内存中的变量和数组中,文件指针向下移动;若读取失败则返回EOF;

char num[20],name[40].sex[5];
FILE *fp;
fp=fopen("e:\\code\\test.txt","rt");
fscanf(fp,"%s %s %s",nnum,name,sex);

(2)格式化读写函数fprintf()
int fprintf("e:\\code\\test.txt","rt");

char num[20]="0402009",name[40]="王瑶晴",sex[5]="女";
FILE*fp;
fp=fopen("e:\\code\\test.txt","a+");
fputc('\n',fp);
fprintf(fp,"%s %s %s",num,name,sex);

注意:如果输入的字符串不带空格,那么读和写都全部正确,但是当输入的字符串中带有空格时,即使向文件中写入的数据依然保持正确,在读取数据时也会发生错误。这是因为fscanf()函数读取数据时以空格作为数据与数据之间的间隔,要解决输入含有空格数据的问题,就必须使用下面要介绍的随机文件读写函数fread()和fwrite();

5、数据块读写操作

(1)数据块读函数fread()

int fread(void *buffer,int size,int count,FILE *fp);
从文件指针fp所指当前位置开始,一次读入size个字节,重复count此,并将数据存到buffer开始的内存区中,同时将读写位置指针后移size*count次,该函数的返回值是实际读取的count值。

各个参数的含义如下:
buffer是一个指针,在fread函数中,它表示存放读入数据的首地址(即存放在何处);在fwrite函数中,它表示要输出的数据在内存中的首地址(要从何处开始存储)。
size它表示数据块的字节数。
count表示要读写的数据块块数。
fp表示文件指针。

float fa[5];
fread(fa,4,5,fp);

表示从fp所指的文件中每次读4个字节,连续读5次,即读五个实数到fa中。

(2)数据块写函数fwrite()

int fwrite(void *buffer,int size,int count,FILE *fp);
从buffer所指向的内存区开始,一次输出size个字节,重复count次,并将输出的数据存入到fp所指的文件中,同时将读写位置指针后移size*count次。

float fa[5];
fwrite(fa,4,5,fp);

例如一个结构体类型数据:

struct student_type{
char name[10};
int num;
int age;
char addr[30];
)stu[40];
//写入文件(前提是stu数组中40个元素都已经有值存在
fwrite(&stu[i],sizeof(struct student_type),40,fp);
//从磁盘文件中读出(前提是fp所指向的文件中也有值存在):
fread(stu,sizeof(struct student_type),40,fp);

注意:fscanf和fprintf是成对出现的,即函数fprintf()写出的文件,要使用函数fscanf()来读入;同理函数fread和fwrite也必须成对出现。

六、文件的随机读写

1、函数rewind()

void rewind(FILE *fp);
将文件内部的位置指针移到文件开始位置

2、函数fseek()

int fseel(FILE *fp,long offsert,int whence);
文件指针有whence地址移到offsert的地址

rewind(fp)
fseek(fp,sizeof(struct stu)*n,0);
fread(&student,sizeof(struct stu),1,fp);

输出第n个位置的数据。

3、函数ftell()

函数ftell()的作用是得到流式文件的当前位置,用相对于文件开头的位移量来表示。如果ftell函数返回值是-1L,则表示出错。

i=ftell(fp);
if(i==-1L) printf("Error\n");
4、其他读写函数

大多数c编译系统的提供另外两个函数putw()和getw(),用来对磁盘文件读一些字(整数)。

//将10输出到fp所指向的文件
putw(10,fp);
// 从磁盘文件中读一个整数到内存,赋给整数变量i
i=getw(fp);

如果c编译的库函数中不包括putw和getw函数,可以自己定义这两个函数。

putw(int i,FILE *fp){
	char *s;
	s=&i;
	putc(s[0],fp);
	putc(s[i],fp);
	return i;
}
getw(FILE *fp){
	char *s;
	int i;
	s=&i;
	s[0]=getc(fp);
	s[1]=getc(fp);
	return i;
}

七、出错检查

1、函数feof()
int feof(FILE *fp);
判断文件指针fp是否处于文件结束位置,若文件结束,则返回1,否则返回0;
2、函数ferror()
int ferror(FILER *fp);
检查文件在用各种输入/输出函数进行读写时是否出错,如果ferror返回值为0表示未出错,否则表示出错。
注意:在同一个文件每一次调用输入/输出函数,均产生一个新的ferror函数值,因此,应当执行fopen函数时,ferror函数的初始值自动置于0;
3、函数clearerr()
int clearerr(FILE *fp);
用于清楚出错标志和文件结束标志,使他们为0。

八、常用的缓冲文件系统函数

在这里插入图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸡不敢说自己菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值