c语言 一个fread完指针指向哪里 想继续fread,[精通C语言]完全分析C文件读写操作....

很多人觉得自己已经很熟悉C文件操作了,而网上的各种文档也大量的介绍了C文件读写操作。但是我没有发现有把fopen的最后一个参数flag的细节和实现机理将的很透彻的。希望我通过一个晚上的试验和总结得到的如下结果可以给大家提供一个完美的C文件读写操作解决方案。

函数fopen的最后一个flag可以是r,w,a,r+,r+,a+。所有上边的属性在某些系统中是需要加b来专门处理二进制文件操作的,但是在linux系统中,Posix标准已经忽略了b的处理,本文讲的是UC编程,所以完全没有必要理会b。下面对每个flag进行讲解,最后重点讲a+,r+,w+。

先看w,r的区别:

w:打开并赋予写权限,没有文件时创建文件,有文件时truncate(清空)源文件

r:打开并赋予读权限,没有文件时返回NULL指针标示错误,errorno设为“can't find

file”对应的错误码。

再来看w+和r+:

都赋予文件读写权限,读写指针均从文件开头开始.区别就是当找不到文件时是否创建文件.

再来详细看看a和a+:

以a打开的文件,开始写时读写指针在文件尾,但是这个指针是不能进行读操作的,会返回无效数据。

技巧:我们可以用a打开文件,直接ftell得到文件大小。而a+则不可以,下面就具体解释。

a+打开后读写指针在什么位置呢?下面将通过试验阐述a+文件内位置指针实现的根本机理:

看下面的代码:

#include

#include

typedef struct

{

int

id;

char

name[20];

float

salary;

}emp;

int main()

{

emp

rec1 = {1, "zz", 1200.5};

emp

rec2 = {2, "zaa", 1200.5};

emp

rec = {};

FILE

*fp = fopen("emp.dat","a+");

if

(fp == NULL)

{

perror("fopen:");

exit(-1);

}

printf("%ld\n",ftell(fp));

//fseek(fp,0,SEEK_END);

//fwrite(&rec1,

sizeof(emp), 1, fp);

//fwrite(&rec2,

sizeof(emp), 1, fp);

printf("%ld\n",ftell(fp));

//fseek(fp,-28,SEEK_END);

//printf("%ld\n",ftell(fp));

fread(&rec,

sizeof(emp), 1, fp);

printf("%d

%s %f\n", rec.id, rec.name, rec.salary);

printf("%ld\n",ftell(fp));

exit(0);

}

结果如下:

bfaf8d731e0f8f51d8d626c2d660b563.png

结果显示:在a+下读取了文件第一个人员信息,读完后文件指针指向28。因为结构体大小是28。很多同学要问,a+打开指针不是在文件尾么?事实上此时位置指针并没有赋值,当你调用fread时,还是会从文件头读取。只有当你调用fwrite时,会把当前指针位置置为文件尾。所以再读什么也读不到了,只有通过fseek才能移动位置指针,继续进行有效的读取。

这就是a+特殊的内部实现机理,因为a+的特殊性而决定的。这种特殊性也就决定了,续写文件时,a+选项是不能边写边修改的,feek指针不能影响fwrite,不能进行复写修改!

而w+和r+则可以进行复写修改!!但是w+会覆盖原文件。

而r+不存在指针跳来跳去的难以控制性,会使代码更容易调试和理解。而且只需要fseek(fp,0,SEEK_END)就可以追加。所以在不考虑安全性的前提下最好的打开文件的方式:r+。

至于文件是不是存在,完全可以用fwrite进行新建后关掉文件后再调用带r+选项的fopen。然后就可以进行随意的读写操作了,控制fseek就像控制鼠标一样。

下面作个简单的模板实现:

#include

#include

typedef struct

{

int

id;

char

name[20];

float

salary;

}emp;

int main()

{

emp

rec1 = {1, "zz", 1200.5};

emp

rec2 = {2, "zaa", 1200.5};

emp

rec = {};

FILE *fp = fopen("emp.dat","a+");//if

create, use "w+"

if

(fp == NULL)

{

perror("fopen:");

exit(-1);

}

fclose(fp);

fp =

fopen("emp.dat","r+");

printf("%ld\n",ftell(fp));

//写3个

fwrite(&rec1,sizeof(rec1),1,fp);

fwrite(&rec2,sizeof(rec2),1,fp);

fwrite(&rec2,sizeof(rec2),1,fp);

//倒回2个

fseek(fp,-56,SEEK_CUR);

//复写一个

fwrite(&rec1,

sizeof(emp), 1, fp);

printf("%ld\n",ftell(fp));

//读最后一个,打印

fread(&rec, sizeof(emp), 1, fp);

printf("%d

%s %f\n", rec.id, rec.name, rec.salary);

exit(0);

}

结果:

131760b2024bd75f1d24587cdd6fd2d1.png

文件:

0ebd318238cd3abf356fa16b27ebd973.png

可以看到第二个单元被成功复写,而第三个单元也被成功打印。没有任何问题!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值